├── .gitignore
├── AndroidManifest.xml
├── project.properties
├── res
└── layout
│ └── main.xml
└── src
└── com
└── exercise
├── AndroidDownloadManager
├── AndroidDownloadManagerActivity.java
└── Sets.java
└── download
├── DownloadManager.java
└── Downloads.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Eclipse project files
19 | .classpath
20 | .project
21 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-15
15 |
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
12 |
18 |
23 |
24 |
--------------------------------------------------------------------------------
/src/com/exercise/AndroidDownloadManager/AndroidDownloadManagerActivity.java:
--------------------------------------------------------------------------------
1 | package com.exercise.AndroidDownloadManager;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileNotFoundException;
6 |
7 | import android.app.Activity;
8 | import com.exercise.download.DownloadManager;
9 | import android.content.BroadcastReceiver;
10 | import android.content.Context;
11 | import android.content.Intent;
12 | import android.content.IntentFilter;
13 | import android.content.SharedPreferences;
14 | import android.content.SharedPreferences.Editor;
15 | import android.database.Cursor;
16 | import android.graphics.Bitmap;
17 | import android.graphics.BitmapFactory;
18 | import android.net.Uri;
19 | import android.os.Bundle;
20 | import android.os.Environment;
21 | import android.os.ParcelFileDescriptor;
22 | import android.preference.PreferenceManager;
23 | import android.view.View;
24 | import android.widget.Button;
25 | import android.widget.ImageView;
26 | import android.widget.Toast;
27 |
28 | import com.exercise.AndroidDownloadManager.R;
29 |
30 | public class AndroidDownloadManagerActivity extends Activity {
31 |
32 | final String DOWNLOAD_FILE = "https://some_url";
33 |
34 | final String strPref_Download_ID = "PREF_DOWNLOAD_ID";
35 |
36 | SharedPreferences preferenceManager;
37 | DownloadManager downloadManager;
38 |
39 | ImageView image;
40 |
41 | /** Called when the activity is first created. */
42 | @Override
43 | public void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.main);
46 |
47 | preferenceManager
48 | = PreferenceManager.getDefaultSharedPreferences(this);
49 | downloadManager
50 | // = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
51 | = new DownloadManager(getContentResolver(), "com.exercise.AndroidDownloadManager");
52 |
53 | Button btnStartDownload = (Button)findViewById(R.id.startdownload);
54 | btnStartDownload.setOnClickListener(btnStartDownloadOnClickListener);
55 |
56 | image = (ImageView)findViewById(R.id.image);
57 | }
58 |
59 | Button.OnClickListener btnStartDownloadOnClickListener
60 | = new Button.OnClickListener(){
61 |
62 | @Override
63 | public void onClick(View v) {
64 | // TODO Auto-generated method stub
65 |
66 | Uri downloadUri = Uri.parse(DOWNLOAD_FILE);
67 | DownloadManager.Request request = new DownloadManager.Request(downloadUri);
68 | request.setDestinationUri(Uri.fromFile(new File( Environment.getExternalStorageDirectory(),"100mb.test.test") ));
69 | long id = downloadManager.enqueue(request);
70 |
71 | //Save the request id
72 | Editor PrefEdit = preferenceManager.edit();
73 | PrefEdit.putLong(strPref_Download_ID, id);
74 | PrefEdit.commit();
75 |
76 | }};
77 |
78 | @Override
79 | protected void onResume() {
80 | // TODO Auto-generated method stub
81 | super.onResume();
82 |
83 | IntentFilter intentFilter
84 | = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
85 | registerReceiver(downloadReceiver, intentFilter);
86 | }
87 |
88 | @Override
89 | protected void onPause() {
90 | // TODO Auto-generated method stub
91 | super.onPause();
92 | unregisterReceiver(downloadReceiver);
93 | }
94 |
95 | private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
96 |
97 | @Override
98 | public void onReceive(Context arg0, Intent arg1) {
99 | CheckDwnloadStatus();
100 | // TODO Auto-generated method stub
101 | DownloadManager.Query query = new DownloadManager.Query();
102 | query.setFilterById(preferenceManager.getLong(strPref_Download_ID, 0));
103 | Cursor cursor = downloadManager.query(query);
104 | if(cursor.moveToFirst()){
105 | int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
106 | int status = cursor.getInt(columnIndex);
107 | if(status == DownloadManager.STATUS_SUCCESSFUL){
108 |
109 | //Retrieve the saved request id
110 | long downloadID = preferenceManager.getLong(strPref_Download_ID, 0);
111 |
112 | ParcelFileDescriptor file;
113 | try {
114 | file = downloadManager.openDownloadedFile(downloadID);
115 | FileInputStream fileInputStream
116 | = new ParcelFileDescriptor.AutoCloseInputStream(file);
117 | Bitmap bm = BitmapFactory.decodeStream(fileInputStream);
118 | image.setImageBitmap(bm);
119 | } catch (FileNotFoundException e) {
120 | // TODO Auto-generated catch block
121 | e.printStackTrace();
122 | }
123 |
124 | }
125 | }
126 | }
127 | };
128 | private void CheckDwnloadStatus(){
129 |
130 | // TODO Auto-generated method stub
131 | DownloadManager.Query query = new DownloadManager.Query();
132 | long id = preferenceManager.getLong(strPref_Download_ID, 0);
133 | query.setFilterById(id);
134 | Cursor cursor = downloadManager.query(query);
135 | if(cursor.moveToFirst()){
136 | int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
137 | int status = cursor.getInt(columnIndex);
138 | int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
139 | int reason = cursor.getInt(columnReason);
140 |
141 | switch(status){
142 | case DownloadManager.STATUS_FAILED:
143 | String failedReason = "";
144 | switch(reason){
145 | case DownloadManager.ERROR_CANNOT_RESUME:
146 | failedReason = "ERROR_CANNOT_RESUME";
147 | break;
148 | case DownloadManager.ERROR_DEVICE_NOT_FOUND:
149 | failedReason = "ERROR_DEVICE_NOT_FOUND";
150 | break;
151 | case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
152 | failedReason = "ERROR_FILE_ALREADY_EXISTS";
153 | break;
154 | case DownloadManager.ERROR_FILE_ERROR:
155 | failedReason = "ERROR_FILE_ERROR";
156 | break;
157 | case DownloadManager.ERROR_HTTP_DATA_ERROR:
158 | failedReason = "ERROR_HTTP_DATA_ERROR";
159 | break;
160 | case DownloadManager.ERROR_INSUFFICIENT_SPACE:
161 | failedReason = "ERROR_INSUFFICIENT_SPACE";
162 | break;
163 | case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
164 | failedReason = "ERROR_TOO_MANY_REDIRECTS";
165 | break;
166 | case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
167 | failedReason = "ERROR_UNHANDLED_HTTP_CODE";
168 | break;
169 | case DownloadManager.ERROR_UNKNOWN:
170 | failedReason = "ERROR_UNKNOWN";
171 | break;
172 | }
173 |
174 | Toast.makeText(AndroidDownloadManagerActivity.this,
175 | "FAILED: " + failedReason,
176 | Toast.LENGTH_LONG).show();
177 | break;
178 | case DownloadManager.STATUS_PAUSED:
179 | String pausedReason = "";
180 |
181 | switch(reason){
182 | case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
183 | pausedReason = "PAUSED_QUEUED_FOR_WIFI";
184 | break;
185 | case DownloadManager.PAUSED_UNKNOWN:
186 | pausedReason = "PAUSED_UNKNOWN";
187 | break;
188 | case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
189 | pausedReason = "PAUSED_WAITING_FOR_NETWORK";
190 | break;
191 | case DownloadManager.PAUSED_WAITING_TO_RETRY:
192 | pausedReason = "PAUSED_WAITING_TO_RETRY";
193 | break;
194 | }
195 |
196 | Toast.makeText(AndroidDownloadManagerActivity.this,
197 | "PAUSED: " + pausedReason,
198 | Toast.LENGTH_LONG).show();
199 | break;
200 | case DownloadManager.STATUS_PENDING:
201 | Toast.makeText(AndroidDownloadManagerActivity.this,
202 | "PENDING",
203 | Toast.LENGTH_LONG).show();
204 | break;
205 | case DownloadManager.STATUS_RUNNING:
206 | Toast.makeText(AndroidDownloadManagerActivity.this,
207 | "RUNNING",
208 | Toast.LENGTH_LONG).show();
209 | break;
210 | case DownloadManager.STATUS_SUCCESSFUL:
211 |
212 | Toast.makeText(AndroidDownloadManagerActivity.this,
213 | "SUCCESSFUL",
214 | Toast.LENGTH_LONG).show();
215 | //GetFile();
216 | break;
217 | }
218 | }
219 | }
220 |
221 | }
--------------------------------------------------------------------------------
/src/com/exercise/AndroidDownloadManager/Sets.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.exercise.AndroidDownloadManager;
18 |
19 | import java.util.Collections;
20 | import java.util.EnumSet;
21 | import java.util.HashSet;
22 | import java.util.SortedSet;
23 | import java.util.TreeSet;
24 |
25 | /**
26 | * Provides static methods for creating mutable {@code Set} instances easily and
27 | * other static methods for working with Sets.
28 | *
29 | */
30 | public class Sets {
31 |
32 | /**
33 | * Creates an empty {@code HashSet} instance.
34 | *
35 | *
Note: if {@code E} is an {@link Enum} type, use {@link
36 | * EnumSet#noneOf} instead.
37 | *
38 | *
Note: if you only need an immutable empty Set,
39 | * use {@link Collections#emptySet} instead.
40 | *
41 | * @return a newly-created, initially-empty {@code HashSet}
42 | */
43 | public static HashSet newHashSet() {
44 | return new HashSet();
45 | }
46 |
47 | /**
48 | * Creates a {@code HashSet} instance containing the given elements.
49 | *
50 | *
Note: due to a bug in javac 1.5.0_06, we cannot support the
51 | * following:
52 | *
53 | *
{@code Set set = Sets.newHashSet(sub1, sub2);}
54 | *
55 | *
where {@code sub1} and {@code sub2} are references to subtypes of {@code
56 | * Base}, not of {@code Base} itself. To get around this, you must use:
57 | *
58 | *
{@code Set set = Sets.newHashSet(sub1, sub2);}
59 | *
60 | * @param elements the elements that the set should contain
61 | * @return a newly-created {@code HashSet} containing those elements (minus
62 | * duplicates)
63 | */
64 | public static HashSet newHashSet(E... elements) {
65 | int capacity = elements.length * 4 / 3 + 1;
66 | HashSet set = new HashSet(capacity);
67 | Collections.addAll(set, elements);
68 | return set;
69 | }
70 |
71 | /**
72 | * Creates an empty {@code SortedSet} instance.
73 | *
74 | * @return a newly-created, initially-empty {@code SortedSet}.
75 | */
76 | public static SortedSet newSortedSet() {
77 | return new TreeSet();
78 | }
79 |
80 | /**
81 | * Creates a {@code SortedSet} instance containing the given elements.
82 | *
83 | * @param elements the elements that the set should contain
84 | * @return a newly-created {@code SortedSet} containing those elements (minus
85 | * duplicates)
86 | */
87 | public static SortedSet newSortedSet(E... elements) {
88 | SortedSet set = new TreeSet();
89 | Collections.addAll(set, elements);
90 | return set;
91 | }
92 |
93 | }
--------------------------------------------------------------------------------
/src/com/exercise/download/DownloadManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.exercise.download;
18 |
19 | import android.content.ContentResolver;
20 | import android.content.ContentUris;
21 | import android.content.ContentValues;
22 | import android.content.Context;
23 | import android.database.Cursor;
24 | import android.database.CursorWrapper;
25 | import android.net.ConnectivityManager;
26 | import android.net.Uri;
27 | import android.os.Environment;
28 | import android.os.ParcelFileDescriptor;
29 | import android.provider.BaseColumns;
30 | //import android.provider.Downloads;
31 | import android.util.Pair;
32 |
33 | import java.io.File;
34 | import java.io.FileNotFoundException;
35 | import java.util.ArrayList;
36 | import java.util.Arrays;
37 | import java.util.HashSet;
38 | import java.util.List;
39 | import java.util.Set;
40 |
41 | /**
42 | * The download manager is a system service that handles long-running HTTP downloads. Clients may
43 | * request that a URI be downloaded to a particular destination file. The download manager will
44 | * conduct the download in the background, taking care of HTTP interactions and retrying downloads
45 | * after failures or across connectivity changes and system reboots.
46 | *
47 | * Instances of this class should be obtained through
48 | * {@link android.content.Context#getSystemService(String)} by passing
49 | * {@link android.content.Context#DOWNLOAD_SERVICE}.
50 | *
51 | * Apps that request downloads through this API should register a broadcast receiver for
52 | * {@link #ACTION_NOTIFICATION_CLICKED} to appropriately handle when the user clicks on a running
53 | * download in a notification or from the downloads UI.
54 | */
55 | public class DownloadManager {
56 | private static final String TAG = "DownloadManager";
57 |
58 | /**
59 | * An identifier for a particular download, unique across the system. Clients use this ID to
60 | * make subsequent calls related to the download.
61 | */
62 | public final static String COLUMN_ID = BaseColumns._ID;
63 |
64 | /**
65 | * The client-supplied title for this download. This will be displayed in system notifications.
66 | * Defaults to the empty string.
67 | */
68 | public final static String COLUMN_TITLE = "title";
69 |
70 | /**
71 | * The client-supplied description of this download. This will be displayed in system
72 | * notifications. Defaults to the empty string.
73 | */
74 | public final static String COLUMN_DESCRIPTION = "description";
75 |
76 | /**
77 | * URI to be downloaded.
78 | */
79 | public final static String COLUMN_URI = "uri";
80 |
81 | /**
82 | * Internet Media Type of the downloaded file. If no value is provided upon creation, this will
83 | * initially be null and will be filled in based on the server's response once the download has
84 | * started.
85 | *
86 | * @see RFC 1590, defining Media Types
87 | */
88 | public final static String COLUMN_MEDIA_TYPE = "media_type";
89 |
90 | /**
91 | * Total size of the download in bytes. This will initially be -1 and will be filled in once
92 | * the download starts.
93 | */
94 | public final static String COLUMN_TOTAL_SIZE_BYTES = "total_size";
95 |
96 | /**
97 | * Uri where downloaded file will be stored. If a destination is supplied by client, that URI
98 | * will be used here. Otherwise, the value will initially be null and will be filled in with a
99 | * generated URI once the download has started.
100 | */
101 | public final static String COLUMN_LOCAL_URI = "local_uri";
102 |
103 | /**
104 | * Current status of the download, as one of the STATUS_* constants.
105 | */
106 | public final static String COLUMN_STATUS = "status";
107 |
108 | /**
109 | * Provides more detail on the status of the download. Its meaning depends on the value of
110 | * {@link #COLUMN_STATUS}.
111 | *
112 | * When {@link #COLUMN_STATUS} is {@link #STATUS_FAILED}, this indicates the type of error that
113 | * occurred. If an HTTP error occurred, this will hold the HTTP status code as defined in RFC
114 | * 2616. Otherwise, it will hold one of the ERROR_* constants.
115 | *
116 | * When {@link #COLUMN_STATUS} is {@link #STATUS_PAUSED}, this indicates why the download is
117 | * paused. It will hold one of the PAUSED_* constants.
118 | *
119 | * If {@link #COLUMN_STATUS} is neither {@link #STATUS_FAILED} nor {@link #STATUS_PAUSED}, this
120 | * column's value is undefined.
121 | *
122 | * @see RFC 2616
123 | * status codes
124 | */
125 | public final static String COLUMN_REASON = "reason";
126 |
127 | /**
128 | * Number of bytes download so far.
129 | */
130 | public final static String COLUMN_BYTES_DOWNLOADED_SO_FAR = "bytes_so_far";
131 |
132 | /**
133 | * Timestamp when the download was last modified, in {@link System#currentTimeMillis
134 | * System.currentTimeMillis()} (wall clock time in UTC).
135 | */
136 | public final static String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
137 |
138 | /**
139 | * The URI to the corresponding entry in MediaProvider for this downloaded entry. It is
140 | * used to delete the entries from MediaProvider database when it is deleted from the
141 | * downloaded list.
142 | */
143 | public static final String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
144 |
145 | /**
146 | * Value of {@link #COLUMN_STATUS} when the download is waiting to start.
147 | */
148 | public final static int STATUS_PENDING = 1 << 0;
149 |
150 | /**
151 | * Value of {@link #COLUMN_STATUS} when the download is currently running.
152 | */
153 | public final static int STATUS_RUNNING = 1 << 1;
154 |
155 | /**
156 | * Value of {@link #COLUMN_STATUS} when the download is waiting to retry or resume.
157 | */
158 | public final static int STATUS_PAUSED = 1 << 2;
159 |
160 | /**
161 | * Value of {@link #COLUMN_STATUS} when the download has successfully completed.
162 | */
163 | public final static int STATUS_SUCCESSFUL = 1 << 3;
164 |
165 | /**
166 | * Value of {@link #COLUMN_STATUS} when the download has failed (and will not be retried).
167 | */
168 | public final static int STATUS_FAILED = 1 << 4;
169 |
170 |
171 | /**
172 | * Value of COLUMN_ERROR_CODE when the download has completed with an error that doesn't fit
173 | * under any other error code.
174 | */
175 | public final static int ERROR_UNKNOWN = 1000;
176 |
177 | /**
178 | * Value of {@link #COLUMN_REASON} when a storage issue arises which doesn't fit under any
179 | * other error code. Use the more specific {@link #ERROR_INSUFFICIENT_SPACE} and
180 | * {@link #ERROR_DEVICE_NOT_FOUND} when appropriate.
181 | */
182 | public final static int ERROR_FILE_ERROR = 1001;
183 |
184 | /**
185 | * Value of {@link #COLUMN_REASON} when an HTTP code was received that download manager
186 | * can't handle.
187 | */
188 | public final static int ERROR_UNHANDLED_HTTP_CODE = 1002;
189 |
190 | /**
191 | * Value of {@link #COLUMN_REASON} when an error receiving or processing data occurred at
192 | * the HTTP level.
193 | */
194 | public final static int ERROR_HTTP_DATA_ERROR = 1004;
195 |
196 | /**
197 | * Value of {@link #COLUMN_REASON} when there were too many redirects.
198 | */
199 | public final static int ERROR_TOO_MANY_REDIRECTS = 1005;
200 |
201 | /**
202 | * Value of {@link #COLUMN_REASON} when there was insufficient storage space. Typically,
203 | * this is because the SD card is full.
204 | */
205 | public final static int ERROR_INSUFFICIENT_SPACE = 1006;
206 |
207 | /**
208 | * Value of {@link #COLUMN_REASON} when no external storage device was found. Typically,
209 | * this is because the SD card is not mounted.
210 | */
211 | public final static int ERROR_DEVICE_NOT_FOUND = 1007;
212 |
213 | /**
214 | * Value of {@link #COLUMN_REASON} when some possibly transient error occurred but we can't
215 | * resume the download.
216 | */
217 | public final static int ERROR_CANNOT_RESUME = 1008;
218 |
219 | /**
220 | * Value of {@link #COLUMN_REASON} when the requested destination file already exists (the
221 | * download manager will not overwrite an existing file).
222 | */
223 | public final static int ERROR_FILE_ALREADY_EXISTS = 1009;
224 |
225 | /**
226 | * Value of {@link #COLUMN_REASON} when the download is paused because some network error
227 | * occurred and the download manager is waiting before retrying the request.
228 | */
229 | public final static int PAUSED_WAITING_TO_RETRY = 1;
230 |
231 | /**
232 | * Value of {@link #COLUMN_REASON} when the download is waiting for network connectivity to
233 | * proceed.
234 | */
235 | public final static int PAUSED_WAITING_FOR_NETWORK = 2;
236 |
237 | /**
238 | * Value of {@link #COLUMN_REASON} when the download exceeds a size limit for downloads over
239 | * the mobile network and the download manager is waiting for a Wi-Fi connection to proceed.
240 | */
241 | public final static int PAUSED_QUEUED_FOR_WIFI = 3;
242 |
243 | /**
244 | * Value of {@link #COLUMN_REASON} when the download is paused for some other reason.
245 | */
246 | public final static int PAUSED_UNKNOWN = 4;
247 |
248 | /**
249 | * Broadcast intent action sent by the download manager when a download completes.
250 | */
251 | public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
252 |
253 | /**
254 | * Broadcast intent action sent by the download manager when the user clicks on a running
255 | * download, either from a system notification or from the downloads UI.
256 | */
257 | public final static String ACTION_NOTIFICATION_CLICKED =
258 | "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
259 |
260 | /**
261 | * Intent action to launch an activity to display all downloads.
262 | */
263 | public final static String ACTION_VIEW_DOWNLOADS = "android.intent.action.VIEW_DOWNLOADS";
264 |
265 | /**
266 | * Intent extra included with {@link #ACTION_DOWNLOAD_COMPLETE} intents, indicating the ID (as a
267 | * long) of the download that just completed.
268 | */
269 | public static final String EXTRA_DOWNLOAD_ID = "extra_download_id";
270 |
271 | // this array must contain all public columns
272 | private static final String[] COLUMNS = new String[] {
273 | COLUMN_ID,
274 | COLUMN_MEDIAPROVIDER_URI,
275 | COLUMN_TITLE,
276 | COLUMN_DESCRIPTION,
277 | COLUMN_URI,
278 | COLUMN_MEDIA_TYPE,
279 | COLUMN_TOTAL_SIZE_BYTES,
280 | COLUMN_LOCAL_URI,
281 | COLUMN_STATUS,
282 | COLUMN_REASON,
283 | COLUMN_BYTES_DOWNLOADED_SO_FAR,
284 | COLUMN_LAST_MODIFIED_TIMESTAMP
285 | };
286 |
287 | // columns to request from DownloadProvider
288 | private static final String[] UNDERLYING_COLUMNS = new String[] {
289 | Downloads.Impl._ID,
290 | Downloads.Impl.COLUMN_MEDIAPROVIDER_URI,
291 | Downloads.COLUMN_TITLE,
292 | Downloads.COLUMN_DESCRIPTION,
293 | Downloads.COLUMN_URI,
294 | Downloads.COLUMN_MIME_TYPE,
295 | Downloads.COLUMN_TOTAL_BYTES,
296 | Downloads.COLUMN_STATUS,
297 | Downloads.COLUMN_CURRENT_BYTES,
298 | Downloads.COLUMN_LAST_MODIFICATION,
299 | Downloads.COLUMN_DESTINATION,
300 | Downloads.Impl.COLUMN_FILE_NAME_HINT,
301 | Downloads.Impl._DATA,
302 | };
303 |
304 | private static final Set LONG_COLUMNS = new HashSet(
305 | Arrays.asList(COLUMN_ID, COLUMN_TOTAL_SIZE_BYTES, COLUMN_STATUS, COLUMN_REASON,
306 | COLUMN_BYTES_DOWNLOADED_SO_FAR, COLUMN_LAST_MODIFIED_TIMESTAMP));
307 |
308 | /**
309 | * This class contains all the information necessary to request a new download. The URI is the
310 | * only required parameter.
311 | *
312 | * Note that the default download destination is a shared volume where the system might delete
313 | * your file if it needs to reclaim space for system use. If this is a problem, use a location
314 | * on external storage (see {@link #setDestinationUri(Uri)}.
315 | */
316 | public static class Request {
317 | /**
318 | * Bit flag for {@link #setAllowedNetworkTypes} corresponding to
319 | * {@link ConnectivityManager#TYPE_MOBILE}.
320 | */
321 | public static final int NETWORK_MOBILE = 1 << 0;
322 |
323 | /**
324 | * Bit flag for {@link #setAllowedNetworkTypes} corresponding to
325 | * {@link ConnectivityManager#TYPE_WIFI}.
326 | */
327 | public static final int NETWORK_WIFI = 1 << 1;
328 |
329 | private Uri mUri;
330 | private Uri mDestinationUri;
331 | private List> mRequestHeaders = new ArrayList>();
332 | private CharSequence mTitle;
333 | private CharSequence mDescription;
334 | private boolean mShowNotification = true;
335 | private String mMimeType;
336 | private boolean mRoamingAllowed = true;
337 | private int mAllowedNetworkTypes = ~0; // default to all network types allowed
338 | private boolean mIsVisibleInDownloadsUi = true;
339 |
340 | /**
341 | * @param uri the HTTP URI to download.
342 | */
343 | public Request(Uri uri) {
344 | if (uri == null) {
345 | throw new NullPointerException();
346 | }
347 | String scheme = uri.getScheme();
348 | if (scheme == null || !(scheme.equals("http") ||scheme.equals("https"))) {
349 | throw new IllegalArgumentException("Can only download HTTP URIs: " + uri);
350 | }
351 | mUri = uri;
352 | }
353 |
354 | /**
355 | * Set the local destination for the downloaded file. Must be a file URI to a path on
356 | * external storage, and the calling application must have the WRITE_EXTERNAL_STORAGE
357 | * permission.
358 | *
359 | * By default, downloads are saved to a generated filename in the shared download cache and
360 | * may be deleted by the system at any time to reclaim space.
361 | *
362 | * @return this object
363 | */
364 | public Request setDestinationUri(Uri uri) {
365 | mDestinationUri = uri;
366 | return this;
367 | }
368 |
369 | /**
370 | * Set the local destination for the downloaded file to a path within the application's
371 | * external files directory (as returned by {@link Context#getExternalFilesDir(String)}.
372 | *
373 | * @param context the {@link Context} to use in determining the external files directory
374 | * @param dirType the directory type to pass to {@link Context#getExternalFilesDir(String)}
375 | * @param subPath the path within the external directory, including the destination filename
376 | * @return this object
377 | */
378 | public Request setDestinationInExternalFilesDir(Context context, String dirType,
379 | String subPath) {
380 | setDestinationFromBase(context.getExternalFilesDir(dirType), subPath);
381 | return this;
382 | }
383 |
384 | /**
385 | * Set the local destination for the downloaded file to a path within the public external
386 | * storage directory (as returned by
387 | * {@link Environment#getExternalStoragePublicDirectory(String)}.
388 | *
389 | * @param dirType the directory type to pass to
390 | * {@link Environment#getExternalStoragePublicDirectory(String)}
391 | * @param subPath the path within the external directory, including the destination filename
392 | * @return this object
393 | */
394 | public Request setDestinationInExternalPublicDir(String dirType, String subPath) {
395 | setDestinationFromBase(Environment.getExternalStoragePublicDirectory(dirType), subPath);
396 | return this;
397 | }
398 |
399 | private void setDestinationFromBase(File base, String subPath) {
400 | if (subPath == null) {
401 | throw new NullPointerException("subPath cannot be null");
402 | }
403 | mDestinationUri = Uri.withAppendedPath(Uri.fromFile(base), subPath);
404 | }
405 |
406 | /**
407 | * Add an HTTP header to be included with the download request. The header will be added to
408 | * the end of the list.
409 | * @param header HTTP header name
410 | * @param value header value
411 | * @return this object
412 | * @see HTTP/1.1
413 | * Message Headers
414 | */
415 | public Request addRequestHeader(String header, String value) {
416 | if (header == null) {
417 | throw new NullPointerException("header cannot be null");
418 | }
419 | if (header.contains(":")) {
420 | throw new IllegalArgumentException("header may not contain ':'");
421 | }
422 | if (value == null) {
423 | value = "";
424 | }
425 | mRequestHeaders.add(Pair.create(header, value));
426 | return this;
427 | }
428 |
429 | /**
430 | * Set the title of this download, to be displayed in notifications (if enabled). If no
431 | * title is given, a default one will be assigned based on the download filename, once the
432 | * download starts.
433 | * @return this object
434 | */
435 | public Request setTitle(CharSequence title) {
436 | mTitle = title;
437 | return this;
438 | }
439 |
440 | /**
441 | * Set a description of this download, to be displayed in notifications (if enabled)
442 | * @return this object
443 | */
444 | public Request setDescription(CharSequence description) {
445 | mDescription = description;
446 | return this;
447 | }
448 |
449 | /**
450 | * Set the MIME content type of this download. This will override the content type declared
451 | * in the server's response.
452 | * @see HTTP/1.1
453 | * Media Types
454 | * @return this object
455 | */
456 | public Request setMimeType(String mimeType) {
457 | mMimeType = mimeType;
458 | return this;
459 | }
460 |
461 | /**
462 | * Control whether a system notification is posted by the download manager while this
463 | * download is running. If enabled, the download manager posts notifications about downloads
464 | * through the system {@link android.app.NotificationManager}. By default, a notification is
465 | * shown.
466 | *
467 | * If set to false, this requires the permission
468 | * android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
469 | *
470 | * @param show whether the download manager should show a notification for this download.
471 | * @return this object
472 | */
473 | public Request setShowRunningNotification(boolean show) {
474 | mShowNotification = show;
475 | return this;
476 | }
477 |
478 | /**
479 | * Restrict the types of networks over which this download may proceed. By default, all
480 | * network types are allowed.
481 | * @param flags any combination of the NETWORK_* bit flags.
482 | * @return this object
483 | */
484 | public Request setAllowedNetworkTypes(int flags) {
485 | mAllowedNetworkTypes = flags;
486 | return this;
487 | }
488 |
489 | /**
490 | * Set whether this download may proceed over a roaming connection. By default, roaming is
491 | * allowed.
492 | * @param allowed whether to allow a roaming connection to be used
493 | * @return this object
494 | */
495 | public Request setAllowedOverRoaming(boolean allowed) {
496 | mRoamingAllowed = allowed;
497 | return this;
498 | }
499 |
500 | /**
501 | * Set whether this download should be displayed in the system's Downloads UI. True by
502 | * default.
503 | * @param isVisible whether to display this download in the Downloads UI
504 | * @return this object
505 | */
506 | public Request setVisibleInDownloadsUi(boolean isVisible) {
507 | mIsVisibleInDownloadsUi = isVisible;
508 | return this;
509 | }
510 |
511 | /**
512 | * @return ContentValues to be passed to DownloadProvider.insert()
513 | */
514 | ContentValues toContentValues(String packageName) {
515 | ContentValues values = new ContentValues();
516 | assert mUri != null;
517 | values.put(Downloads.COLUMN_URI, mUri.toString());
518 | values.put(Downloads.Impl.COLUMN_IS_PUBLIC_API, true);
519 | values.put(Downloads.COLUMN_NOTIFICATION_PACKAGE, packageName);
520 |
521 | if (mDestinationUri != null) {
522 | values.put(Downloads.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_FILE_URI);
523 | values.put(Downloads.COLUMN_FILE_NAME_HINT, mDestinationUri.toString());
524 | } else {
525 | values.put(Downloads.COLUMN_DESTINATION,
526 | Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE);
527 | }
528 |
529 | if (!mRequestHeaders.isEmpty()) {
530 | encodeHttpHeaders(values);
531 | }
532 |
533 | putIfNonNull(values, Downloads.COLUMN_TITLE, mTitle);
534 | putIfNonNull(values, Downloads.COLUMN_DESCRIPTION, mDescription);
535 | putIfNonNull(values, Downloads.COLUMN_MIME_TYPE, mMimeType);
536 |
537 | values.put(Downloads.COLUMN_VISIBILITY,
538 | mShowNotification ? Downloads.VISIBILITY_VISIBLE
539 | : Downloads.VISIBILITY_HIDDEN);
540 |
541 | values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, mAllowedNetworkTypes);
542 | values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, mRoamingAllowed);
543 | values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, mIsVisibleInDownloadsUi);
544 |
545 | return values;
546 | }
547 |
548 | private void encodeHttpHeaders(ContentValues values) {
549 | int index = 0;
550 | for (Pair header : mRequestHeaders) {
551 | String headerString = header.first + ": " + header.second;
552 | values.put(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX + index, headerString);
553 | index++;
554 | }
555 | }
556 |
557 | private void putIfNonNull(ContentValues contentValues, String key, Object value) {
558 | if (value != null) {
559 | contentValues.put(key, value.toString());
560 | }
561 | }
562 | }
563 |
564 | /**
565 | * This class may be used to filter download manager queries.
566 | */
567 | public static class Query {
568 | /**
569 | * Constant for use with {@link #orderBy}
570 | * @hide
571 | */
572 | public static final int ORDER_ASCENDING = 1;
573 |
574 | /**
575 | * Constant for use with {@link #orderBy}
576 | * @hide
577 | */
578 | public static final int ORDER_DESCENDING = 2;
579 |
580 | private long[] mIds = null;
581 | private Integer mStatusFlags = null;
582 | private String mOrderByColumn = Downloads.COLUMN_LAST_MODIFICATION;
583 | private int mOrderDirection = ORDER_DESCENDING;
584 | private boolean mOnlyIncludeVisibleInDownloadsUi = false;
585 |
586 | /**
587 | * Include only the downloads with the given IDs.
588 | * @return this object
589 | */
590 | public Query setFilterById(long... ids) {
591 | mIds = ids;
592 | return this;
593 | }
594 |
595 | /**
596 | * Include only downloads with status matching any the given status flags.
597 | * @param flags any combination of the STATUS_* bit flags
598 | * @return this object
599 | */
600 | public Query setFilterByStatus(int flags) {
601 | mStatusFlags = flags;
602 | return this;
603 | }
604 |
605 | /**
606 | * Controls whether this query includes downloads not visible in the system's Downloads UI.
607 | * @param value if true, this query will only include downloads that should be displayed in
608 | * the system's Downloads UI; if false (the default), this query will include
609 | * both visible and invisible downloads.
610 | * @return this object
611 | * @hide
612 | */
613 | public Query setOnlyIncludeVisibleInDownloadsUi(boolean value) {
614 | mOnlyIncludeVisibleInDownloadsUi = value;
615 | return this;
616 | }
617 |
618 | /**
619 | * Change the sort order of the returned Cursor.
620 | *
621 | * @param column one of the COLUMN_* constants; currently, only
622 | * {@link #COLUMN_LAST_MODIFIED_TIMESTAMP} and {@link #COLUMN_TOTAL_SIZE_BYTES} are
623 | * supported.
624 | * @param direction either {@link #ORDER_ASCENDING} or {@link #ORDER_DESCENDING}
625 | * @return this object
626 | * @hide
627 | */
628 | public Query orderBy(String column, int direction) {
629 | if (direction != ORDER_ASCENDING && direction != ORDER_DESCENDING) {
630 | throw new IllegalArgumentException("Invalid direction: " + direction);
631 | }
632 |
633 | if (column.equals(COLUMN_LAST_MODIFIED_TIMESTAMP)) {
634 | mOrderByColumn = Downloads.COLUMN_LAST_MODIFICATION;
635 | } else if (column.equals(COLUMN_TOTAL_SIZE_BYTES)) {
636 | mOrderByColumn = Downloads.COLUMN_TOTAL_BYTES;
637 | } else {
638 | throw new IllegalArgumentException("Cannot order by " + column);
639 | }
640 | mOrderDirection = direction;
641 | return this;
642 | }
643 |
644 | /**
645 | * Run this query using the given ContentResolver.
646 | * @param projection the projection to pass to ContentResolver.query()
647 | * @return the Cursor returned by ContentResolver.query()
648 | */
649 | Cursor runQuery(ContentResolver resolver, String[] projection, Uri baseUri) {
650 | Uri uri = baseUri;
651 | List selectionParts = new ArrayList();
652 | String[] selectionArgs = null;
653 |
654 | if (mIds != null) {
655 | selectionParts.add(getWhereClauseForIds(mIds));
656 | selectionArgs = getWhereArgsForIds(mIds);
657 | }
658 |
659 | if (mStatusFlags != null) {
660 | List parts = new ArrayList();
661 | if ((mStatusFlags & STATUS_PENDING) != 0) {
662 | parts.add(statusClause("=", Downloads.STATUS_PENDING));
663 | }
664 | if ((mStatusFlags & STATUS_RUNNING) != 0) {
665 | parts.add(statusClause("=", Downloads.STATUS_RUNNING));
666 | }
667 | if ((mStatusFlags & STATUS_PAUSED) != 0) {
668 | parts.add(statusClause("=", Downloads.Impl.STATUS_PAUSED_BY_APP));
669 | parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_TO_RETRY));
670 | parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_FOR_NETWORK));
671 | parts.add(statusClause("=", Downloads.Impl.STATUS_QUEUED_FOR_WIFI));
672 | }
673 | if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
674 | parts.add(statusClause("=", Downloads.STATUS_SUCCESS));
675 | }
676 | if ((mStatusFlags & STATUS_FAILED) != 0) {
677 | parts.add("(" + statusClause(">=", 400)
678 | + " AND " + statusClause("<", 600) + ")");
679 | }
680 | selectionParts.add(joinStrings(" OR ", parts));
681 | }
682 |
683 | if (mOnlyIncludeVisibleInDownloadsUi) {
684 | selectionParts.add(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI + " != '0'");
685 | }
686 |
687 | // only return rows which are not marked 'deleted = 1'
688 | selectionParts.add(Downloads.Impl.COLUMN_DELETED + " != '1'");
689 |
690 | String selection = joinStrings(" AND ", selectionParts);
691 | String orderDirection = (mOrderDirection == ORDER_ASCENDING ? "ASC" : "DESC");
692 | String orderBy = mOrderByColumn + " " + orderDirection;
693 |
694 | return resolver.query(uri, projection, selection, selectionArgs, orderBy);
695 | }
696 |
697 | private String joinStrings(String joiner, Iterable parts) {
698 | StringBuilder builder = new StringBuilder();
699 | boolean first = true;
700 | for (String part : parts) {
701 | if (!first) {
702 | builder.append(joiner);
703 | }
704 | builder.append(part);
705 | first = false;
706 | }
707 | return builder.toString();
708 | }
709 |
710 | private String statusClause(String operator, int value) {
711 | return Downloads.COLUMN_STATUS + operator + "'" + value + "'";
712 | }
713 | }
714 |
715 | private ContentResolver mResolver;
716 | private String mPackageName;
717 | private Uri mBaseUri = Downloads.Impl.CONTENT_URI;
718 |
719 | /**
720 | * @hide
721 | */
722 | public DownloadManager(ContentResolver resolver, String packageName) {
723 | mResolver = resolver;
724 | mPackageName = packageName;
725 | }
726 |
727 | /**
728 | * Makes this object access the download provider through /all_downloads URIs rather than
729 | * /my_downloads URIs, for clients that have permission to do so.
730 | * @hide
731 | */
732 | public void setAccessAllDownloads(boolean accessAllDownloads) {
733 | if (accessAllDownloads) {
734 | mBaseUri = Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI;
735 | } else {
736 | mBaseUri = Downloads.Impl.CONTENT_URI;
737 | }
738 | }
739 |
740 | /**
741 | * Enqueue a new download. The download will start automatically once the download manager is
742 | * ready to execute it and connectivity is available.
743 | *
744 | * @param request the parameters specifying this download
745 | * @return an ID for the download, unique across the system. This ID is used to make future
746 | * calls related to this download.
747 | */
748 | public long enqueue(Request request) {
749 | ContentValues values = request.toContentValues(mPackageName);
750 | Uri downloadUri = mResolver.insert(Downloads.CONTENT_URI, values);
751 | long id = Long.parseLong(downloadUri.getLastPathSegment());
752 | return id;
753 | }
754 |
755 | /**
756 | * Marks the specified download as 'to be deleted'. This is done when a completed download
757 | * is to be removed but the row was stored without enough info to delete the corresponding
758 | * metadata from Mediaprovider database. Actual cleanup of this row is done in DownloadService.
759 | *
760 | * @param ids the IDs of the downloads to be marked 'deleted'
761 | * @return the number of downloads actually updated
762 | * @hide
763 | */
764 | public int markRowDeleted(long... ids) {
765 | if (ids == null || ids.length == 0) {
766 | // called with nothing to remove!
767 | throw new IllegalArgumentException("input param 'ids' can't be null");
768 | }
769 | ContentValues values = new ContentValues();
770 | values.put(Downloads.Impl.COLUMN_DELETED, 1);
771 | return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
772 | getWhereArgsForIds(ids));
773 | }
774 |
775 | /**
776 | * Cancel downloads and remove them from the download manager. Each download will be stopped if
777 | * it was running, and it will no longer be accessible through the download manager. If a file
778 | * was already downloaded to external storage, it will not be deleted.
779 | *
780 | * @param ids the IDs of the downloads to remove
781 | * @return the number of downloads actually removed
782 | */
783 | public int remove(long... ids) {
784 | if (ids == null || ids.length == 0) {
785 | // called with nothing to remove!
786 | throw new IllegalArgumentException("input param 'ids' can't be null");
787 | }
788 | return mResolver.delete(mBaseUri, getWhereClauseForIds(ids), getWhereArgsForIds(ids));
789 | }
790 |
791 | /**
792 | * Query the download manager about downloads that have been requested.
793 | * @param query parameters specifying filters for this query
794 | * @return a Cursor over the result set of downloads, with columns consisting of all the
795 | * COLUMN_* constants.
796 | */
797 | public Cursor query(Query query) {
798 | Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS, mBaseUri);
799 | if (underlyingCursor == null) {
800 | return null;
801 | }
802 | return new CursorTranslator(underlyingCursor, mBaseUri);
803 | }
804 |
805 | /**
806 | * Open a downloaded file for reading. The download must have completed.
807 | * @param id the ID of the download
808 | * @return a read-only {@link ParcelFileDescriptor}
809 | * @throws FileNotFoundException if the destination file does not already exist
810 | */
811 | public ParcelFileDescriptor openDownloadedFile(long id) throws FileNotFoundException {
812 | return mResolver.openFileDescriptor(getDownloadUri(id), "r");
813 | }
814 |
815 | /**
816 | * Restart the given downloads, which must have already completed (successfully or not). This
817 | * method will only work when called from within the download manager's process.
818 | * @param ids the IDs of the downloads
819 | * @hide
820 | */
821 | public void restartDownload(long... ids) {
822 | Cursor cursor = query(new Query().setFilterById(ids));
823 | try {
824 | for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
825 | int status = cursor.getInt(cursor.getColumnIndex(COLUMN_STATUS));
826 | if (status != STATUS_SUCCESSFUL && status != STATUS_FAILED) {
827 | throw new IllegalArgumentException("Cannot restart incomplete download: "
828 | + cursor.getLong(cursor.getColumnIndex(COLUMN_ID)));
829 | }
830 | }
831 | } finally {
832 | cursor.close();
833 | }
834 |
835 | ContentValues values = new ContentValues();
836 | values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0);
837 | values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1);
838 | values.putNull(Downloads.Impl._DATA);
839 | values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING);
840 | mResolver.update(mBaseUri, values, getWhereClauseForIds(ids), getWhereArgsForIds(ids));
841 | }
842 |
843 | /**
844 | * Get the DownloadProvider URI for the download with the given ID.
845 | */
846 | Uri getDownloadUri(long id) {
847 | return ContentUris.withAppendedId(mBaseUri, id);
848 | }
849 |
850 | /**
851 | * Get a parameterized SQL WHERE clause to select a bunch of IDs.
852 | */
853 | static String getWhereClauseForIds(long[] ids) {
854 | StringBuilder whereClause = new StringBuilder();
855 | whereClause.append("(");
856 | for (int i = 0; i < ids.length; i++) {
857 | if (i > 0) {
858 | whereClause.append("OR ");
859 | }
860 | whereClause.append(Downloads.Impl._ID);
861 | whereClause.append(" = ? ");
862 | }
863 | whereClause.append(")");
864 | return whereClause.toString();
865 | }
866 |
867 | /**
868 | * Get the selection args for a clause returned by {@link #getWhereClauseForIds(long[])}.
869 | */
870 | static String[] getWhereArgsForIds(long[] ids) {
871 | String[] whereArgs = new String[ids.length];
872 | for (int i = 0; i < ids.length; i++) {
873 | whereArgs[i] = Long.toString(ids[i]);
874 | }
875 | return whereArgs;
876 | }
877 |
878 | /**
879 | * This class wraps a cursor returned by DownloadProvider -- the "underlying cursor" -- and
880 | * presents a different set of columns, those defined in the DownloadManager.COLUMN_* constants.
881 | * Some columns correspond directly to underlying values while others are computed from
882 | * underlying data.
883 | */
884 | private static class CursorTranslator extends CursorWrapper {
885 | private Uri mBaseUri;
886 |
887 | public CursorTranslator(Cursor cursor, Uri baseUri) {
888 | super(cursor);
889 | mBaseUri = baseUri;
890 | }
891 |
892 | @Override
893 | public int getColumnIndex(String columnName) {
894 | return Arrays.asList(COLUMNS).indexOf(columnName);
895 | }
896 |
897 | @Override
898 | public int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException {
899 | int index = getColumnIndex(columnName);
900 | if (index == -1) {
901 | throw new IllegalArgumentException("No such column: " + columnName);
902 | }
903 | return index;
904 | }
905 |
906 | @Override
907 | public String getColumnName(int columnIndex) {
908 | int numColumns = COLUMNS.length;
909 | if (columnIndex < 0 || columnIndex >= numColumns) {
910 | throw new IllegalArgumentException("Invalid column index " + columnIndex + ", "
911 | + numColumns + " columns exist");
912 | }
913 | return COLUMNS[columnIndex];
914 | }
915 |
916 | @Override
917 | public String[] getColumnNames() {
918 | String[] returnColumns = new String[COLUMNS.length];
919 | System.arraycopy(COLUMNS, 0, returnColumns, 0, COLUMNS.length);
920 | return returnColumns;
921 | }
922 |
923 | @Override
924 | public int getColumnCount() {
925 | return COLUMNS.length;
926 | }
927 |
928 | @Override
929 | public byte[] getBlob(int columnIndex) {
930 | throw new UnsupportedOperationException();
931 | }
932 |
933 | @Override
934 | public double getDouble(int columnIndex) {
935 | return getLong(columnIndex);
936 | }
937 |
938 | private boolean isLongColumn(String column) {
939 | return LONG_COLUMNS.contains(column);
940 | }
941 |
942 | @Override
943 | public float getFloat(int columnIndex) {
944 | return (float) getDouble(columnIndex);
945 | }
946 |
947 | @Override
948 | public int getInt(int columnIndex) {
949 | return (int) getLong(columnIndex);
950 | }
951 |
952 | @Override
953 | public long getLong(int columnIndex) {
954 | return translateLong(getColumnName(columnIndex));
955 | }
956 |
957 | @Override
958 | public short getShort(int columnIndex) {
959 | return (short) getLong(columnIndex);
960 | }
961 |
962 | @Override
963 | public String getString(int columnIndex) {
964 | return translateString(getColumnName(columnIndex));
965 | }
966 |
967 | private String translateString(String column) {
968 | if (isLongColumn(column)) {
969 | return Long.toString(translateLong(column));
970 | }
971 | if (column.equals(COLUMN_TITLE)) {
972 | return getUnderlyingString(Downloads.COLUMN_TITLE);
973 | }
974 | if (column.equals(COLUMN_DESCRIPTION)) {
975 | return getUnderlyingString(Downloads.COLUMN_DESCRIPTION);
976 | }
977 | if (column.equals(COLUMN_URI)) {
978 | return getUnderlyingString(Downloads.COLUMN_URI);
979 | }
980 | if (column.equals(COLUMN_MEDIA_TYPE)) {
981 | return getUnderlyingString(Downloads.COLUMN_MIME_TYPE);
982 | }
983 | if (column.equals(COLUMN_MEDIAPROVIDER_URI)) {
984 | return getUnderlyingString(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI);
985 | }
986 |
987 | assert column.equals(COLUMN_LOCAL_URI);
988 | return getLocalUri();
989 | }
990 |
991 | private String getLocalUri() {
992 | long destinationType = getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION);
993 | if (destinationType == Downloads.Impl.DESTINATION_FILE_URI) {
994 | // return client-provided file URI for external download
995 | return getUnderlyingString(Downloads.Impl.COLUMN_FILE_NAME_HINT);
996 | }
997 |
998 | if (destinationType == Downloads.Impl.DESTINATION_EXTERNAL) {
999 | // return stored destination for legacy external download
1000 | String localPath = getUnderlyingString(Downloads.Impl._DATA);
1001 | if (localPath == null) {
1002 | return null;
1003 | }
1004 | return Uri.fromFile(new File(localPath)).toString();
1005 | }
1006 |
1007 | // return content URI for cache download
1008 | long downloadId = getUnderlyingLong(Downloads.Impl._ID);
1009 | return ContentUris.withAppendedId(mBaseUri, downloadId).toString();
1010 | }
1011 |
1012 | private long translateLong(String column) {
1013 | if (!isLongColumn(column)) {
1014 | // mimic behavior of underlying cursor -- most likely, throw NumberFormatException
1015 | return Long.valueOf(translateString(column));
1016 | }
1017 |
1018 | if (column.equals(COLUMN_ID)) {
1019 | return getUnderlyingLong(Downloads.Impl._ID);
1020 | }
1021 | if (column.equals(COLUMN_TOTAL_SIZE_BYTES)) {
1022 | return getUnderlyingLong(Downloads.COLUMN_TOTAL_BYTES);
1023 | }
1024 | if (column.equals(COLUMN_STATUS)) {
1025 | return translateStatus((int) getUnderlyingLong(Downloads.COLUMN_STATUS));
1026 | }
1027 | if (column.equals(COLUMN_REASON)) {
1028 | return getReason((int) getUnderlyingLong(Downloads.COLUMN_STATUS));
1029 | }
1030 | if (column.equals(COLUMN_BYTES_DOWNLOADED_SO_FAR)) {
1031 | return getUnderlyingLong(Downloads.COLUMN_CURRENT_BYTES);
1032 | }
1033 | assert column.equals(COLUMN_LAST_MODIFIED_TIMESTAMP);
1034 | return getUnderlyingLong(Downloads.COLUMN_LAST_MODIFICATION);
1035 | }
1036 |
1037 | private long getReason(int status) {
1038 | switch (translateStatus(status)) {
1039 | case STATUS_FAILED:
1040 | return getErrorCode(status);
1041 |
1042 | case STATUS_PAUSED:
1043 | return getPausedReason(status);
1044 |
1045 | default:
1046 | return 0; // arbitrary value when status is not an error
1047 | }
1048 | }
1049 |
1050 | private long getPausedReason(int status) {
1051 | switch (status) {
1052 | case Downloads.Impl.STATUS_WAITING_TO_RETRY:
1053 | return PAUSED_WAITING_TO_RETRY;
1054 |
1055 | case Downloads.Impl.STATUS_WAITING_FOR_NETWORK:
1056 | return PAUSED_WAITING_FOR_NETWORK;
1057 |
1058 | case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
1059 | return PAUSED_QUEUED_FOR_WIFI;
1060 |
1061 | default:
1062 | return PAUSED_UNKNOWN;
1063 | }
1064 | }
1065 |
1066 | private long getErrorCode(int status) {
1067 | if ((400 <= status && status < Downloads.Impl.MIN_ARTIFICIAL_ERROR_STATUS)
1068 | || (500 <= status && status < 600)) {
1069 | // HTTP status code
1070 | return status;
1071 | }
1072 |
1073 | switch (status) {
1074 | case Downloads.STATUS_FILE_ERROR:
1075 | return ERROR_FILE_ERROR;
1076 |
1077 | case Downloads.STATUS_UNHANDLED_HTTP_CODE:
1078 | case Downloads.STATUS_UNHANDLED_REDIRECT:
1079 | return ERROR_UNHANDLED_HTTP_CODE;
1080 |
1081 | case Downloads.STATUS_HTTP_DATA_ERROR:
1082 | return ERROR_HTTP_DATA_ERROR;
1083 |
1084 | case Downloads.STATUS_TOO_MANY_REDIRECTS:
1085 | return ERROR_TOO_MANY_REDIRECTS;
1086 |
1087 | case Downloads.STATUS_INSUFFICIENT_SPACE_ERROR:
1088 | return ERROR_INSUFFICIENT_SPACE;
1089 |
1090 | case Downloads.STATUS_DEVICE_NOT_FOUND_ERROR:
1091 | return ERROR_DEVICE_NOT_FOUND;
1092 |
1093 | case Downloads.Impl.STATUS_CANNOT_RESUME:
1094 | return ERROR_CANNOT_RESUME;
1095 |
1096 | case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR:
1097 | return ERROR_FILE_ALREADY_EXISTS;
1098 |
1099 | default:
1100 | return ERROR_UNKNOWN;
1101 | }
1102 | }
1103 |
1104 | private long getUnderlyingLong(String column) {
1105 | return super.getLong(super.getColumnIndex(column));
1106 | }
1107 |
1108 | private String getUnderlyingString(String column) {
1109 | return super.getString(super.getColumnIndex(column));
1110 | }
1111 |
1112 | private int translateStatus(int status) {
1113 | switch (status) {
1114 | case Downloads.STATUS_PENDING:
1115 | return STATUS_PENDING;
1116 |
1117 | case Downloads.STATUS_RUNNING:
1118 | return STATUS_RUNNING;
1119 |
1120 | case Downloads.Impl.STATUS_PAUSED_BY_APP:
1121 | case Downloads.Impl.STATUS_WAITING_TO_RETRY:
1122 | case Downloads.Impl.STATUS_WAITING_FOR_NETWORK:
1123 | case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
1124 | return STATUS_PAUSED;
1125 |
1126 | case Downloads.STATUS_SUCCESS:
1127 | return STATUS_SUCCESSFUL;
1128 |
1129 | default:
1130 | assert Downloads.isStatusError(status);
1131 | return STATUS_FAILED;
1132 | }
1133 | }
1134 | }
1135 | }
--------------------------------------------------------------------------------
/src/com/exercise/download/Downloads.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.exercise.download;
18 |
19 | import android.net.Uri;
20 | import android.provider.BaseColumns;
21 |
22 | /**
23 | * The Download Manager
24 | *
25 | * @pending
26 | */
27 | public final class Downloads {
28 | /**
29 | * @hide
30 | */
31 | private Downloads() {}
32 |
33 | /**
34 | * The permission to access the download manager
35 | * @hide
36 | */
37 | public static final String PERMISSION_ACCESS = "android.permission.ACCESS_DOWNLOAD_MANAGER";
38 |
39 | /**
40 | * The permission to access the download manager's advanced functions
41 | * @hide
42 | */
43 | public static final String PERMISSION_ACCESS_ADVANCED =
44 | "android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED";
45 |
46 | /**
47 | * The permission to directly access the download manager's cache directory
48 | * @hide
49 | */
50 | public static final String PERMISSION_CACHE = "android.permission.ACCESS_CACHE_FILESYSTEM";
51 |
52 | /**
53 | * The permission to send broadcasts on download completion
54 | * @hide
55 | */
56 | public static final String PERMISSION_SEND_INTENTS =
57 | "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS";
58 |
59 | /**
60 | * The content:// URI for the data table in the provider
61 | * @hide
62 | */
63 | public static final Uri CONTENT_URI =
64 | Uri.parse("content://downloads/my_downloads");
65 |
66 | /**
67 | * Broadcast Action: this is sent by the download manager to the app
68 | * that had initiated a download when that download completes. The
69 | * download's content: uri is specified in the intent's data.
70 | * @hide
71 | */
72 | public static final String ACTION_DOWNLOAD_COMPLETED =
73 | "android.intent.action.DOWNLOAD_COMPLETED";
74 |
75 | /**
76 | * Broadcast Action: this is sent by the download manager to the app
77 | * that had initiated a download when the user selects the notification
78 | * associated with that download. The download's content: uri is specified
79 | * in the intent's data if the click is associated with a single download,
80 | * or Downloads.CONTENT_URI if the notification is associated with
81 | * multiple downloads.
82 | * Note: this is not currently sent for downloads that have completed
83 | * successfully.
84 | * @hide
85 | */
86 | public static final String ACTION_NOTIFICATION_CLICKED =
87 | "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
88 |
89 | /**
90 | * The name of the column containing the URI of the data being downloaded.
91 | *
Type: TEXT
92 | *
Owner can Init/Read
93 | * @hide
94 | */
95 | public static final String COLUMN_URI = "uri";
96 |
97 | /**
98 | * The name of the column containing application-specific data.
99 | *
Type: TEXT
100 | *
Owner can Init/Read/Write
101 | * @hide
102 | */
103 | public static final String COLUMN_APP_DATA = "entity";
104 |
105 | /**
106 | * The name of the column containing the flags that indicates whether
107 | * the initiating application is capable of verifying the integrity of
108 | * the downloaded file. When this flag is set, the download manager
109 | * performs downloads and reports success even in some situations where
110 | * it can't guarantee that the download has completed (e.g. when doing
111 | * a byte-range request without an ETag, or when it can't determine
112 | * whether a download fully completed).
113 | *
Type: BOOLEAN
114 | *
Owner can Init
115 | * @hide
116 | */
117 | public static final String COLUMN_NO_INTEGRITY = "no_integrity";
118 |
119 | /**
120 | * The name of the column containing the filename that the initiating
121 | * application recommends. When possible, the download manager will attempt
122 | * to use this filename, or a variation, as the actual name for the file.
123 | *
Type: TEXT
124 | *
Owner can Init
125 | * @hide
126 | */
127 | public static final String COLUMN_FILE_NAME_HINT = "hint";
128 |
129 | /**
130 | * The name of the column containing the filename where the downloaded data
131 | * was actually stored.
132 | *
Type: TEXT
133 | *
Owner can Read
134 | * @hide
135 | */
136 | public static final String _DATA = "_data";
137 |
138 | /**
139 | * The name of the column containing the MIME type of the downloaded data.
140 | *
Type: TEXT
141 | *
Owner can Init/Read
142 | * @hide
143 | */
144 | public static final String COLUMN_MIME_TYPE = "mimetype";
145 |
146 | /**
147 | * The name of the column containing the flag that controls the destination
148 | * of the download. See the DESTINATION_* constants for a list of legal values.
149 | *
Type: INTEGER
150 | *
Owner can Init
151 | * @hide
152 | */
153 | public static final String COLUMN_DESTINATION = "destination";
154 |
155 | /**
156 | * The name of the column containing the flags that controls whether the
157 | * download is displayed by the UI. See the VISIBILITY_* constants for
158 | * a list of legal values.
159 | *
Type: INTEGER
160 | *
Owner can Init/Read/Write
161 | * @hide
162 | */
163 | public static final String COLUMN_VISIBILITY = "visibility";
164 |
165 | /**
166 | * The name of the column containing the current control state of the download.
167 | * Applications can write to this to control (pause/resume) the download.
168 | * the CONTROL_* constants for a list of legal values.
169 | *
Type: INTEGER
170 | *
Owner can Read
171 | * @hide
172 | */
173 | public static final String COLUMN_CONTROL = "control";
174 |
175 | /**
176 | * The name of the column containing the current status of the download.
177 | * Applications can read this to follow the progress of each download. See
178 | * the STATUS_* constants for a list of legal values.
179 | *
Type: INTEGER
180 | *
Owner can Read
181 | * @hide
182 | */
183 | public static final String COLUMN_STATUS = "status";
184 |
185 | /**
186 | * The name of the column containing the date at which some interesting
187 | * status changed in the download. Stored as a System.currentTimeMillis()
188 | * value.
189 | *
Type: BIGINT
190 | *
Owner can Read
191 | * @hide
192 | */
193 | public static final String COLUMN_LAST_MODIFICATION = "lastmod";
194 |
195 | /**
196 | * The name of the column containing the package name of the application
197 | * that initiating the download. The download manager will send
198 | * notifications to a component in this package when the download completes.
199 | *
Type: TEXT
200 | *
Owner can Init/Read
201 | * @hide
202 | */
203 | public static final String COLUMN_NOTIFICATION_PACKAGE = "notificationpackage";
204 |
205 | /**
206 | * The name of the column containing the component name of the class that
207 | * will receive notifications associated with the download. The
208 | * package/class combination is passed to
209 | * Intent.setClassName(String,String).
210 | *
Type: TEXT
211 | *
Owner can Init/Read
212 | * @hide
213 | */
214 | public static final String COLUMN_NOTIFICATION_CLASS = "notificationclass";
215 |
216 | /**
217 | * If extras are specified when requesting a download they will be provided in the intent that
218 | * is sent to the specified class and package when a download has finished.
219 | *
Type: TEXT
220 | *
Owner can Init
221 | * @hide
222 | */
223 | public static final String COLUMN_NOTIFICATION_EXTRAS = "notificationextras";
224 |
225 | /**
226 | * The name of the column contain the values of the cookie to be used for
227 | * the download. This is used directly as the value for the Cookie: HTTP
228 | * header that gets sent with the request.
229 | *
Type: TEXT
230 | *
Owner can Init
231 | * @hide
232 | */
233 | public static final String COLUMN_COOKIE_DATA = "cookiedata";
234 |
235 | /**
236 | * The name of the column containing the user agent that the initiating
237 | * application wants the download manager to use for this download.
238 | *
Type: TEXT
239 | *
Owner can Init
240 | * @hide
241 | */
242 | public static final String COLUMN_USER_AGENT = "useragent";
243 |
244 | /**
245 | * The name of the column containing the referer (sic) that the initiating
246 | * application wants the download manager to use for this download.
247 | *
Type: TEXT
248 | *
Owner can Init
249 | * @hide
250 | */
251 | public static final String COLUMN_REFERER = "referer";
252 |
253 | /**
254 | * The name of the column containing the total size of the file being
255 | * downloaded.
256 | *
Type: INTEGER
257 | *
Owner can Read
258 | * @hide
259 | */
260 | public static final String COLUMN_TOTAL_BYTES = "total_bytes";
261 |
262 | /**
263 | * The name of the column containing the size of the part of the file that
264 | * has been downloaded so far.
265 | *
Type: INTEGER
266 | *
Owner can Read
267 | * @hide
268 | */
269 | public static final String COLUMN_CURRENT_BYTES = "current_bytes";
270 |
271 | /**
272 | * The name of the column where the initiating application can provide the
273 | * UID of another application that is allowed to access this download. If
274 | * multiple applications share the same UID, all those applications will be
275 | * allowed to access this download. This column can be updated after the
276 | * download is initiated. This requires the permission
277 | * android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED.
278 | *
Type: INTEGER
279 | *
Owner can Init
280 | * @hide
281 | */
282 | public static final String COLUMN_OTHER_UID = "otheruid";
283 |
284 | /**
285 | * The name of the column where the initiating application can provided the
286 | * title of this download. The title will be displayed ito the user in the
287 | * list of downloads.
288 | *
Type: TEXT
289 | *
Owner can Init/Read/Write
290 | * @hide
291 | */
292 | public static final String COLUMN_TITLE = "title";
293 |
294 | /**
295 | * The name of the column where the initiating application can provide the
296 | * description of this download. The description will be displayed to the
297 | * user in the list of downloads.
298 | *
Type: TEXT
299 | *
Owner can Init/Read/Write
300 | * @hide
301 | */
302 | public static final String COLUMN_DESCRIPTION = "description";
303 |
304 | /**
305 | * Set to true if this download is deleted. It is completely removed from the database
306 | * when MediaProvider database also deletes the metadata asociated with this downloaded file.
307 | *
Type: BOOLEAN
308 | *
Owner can Read
309 | * @hide
310 | */
311 | public static final String COLUMN_DELETED = "deleted";
312 |
313 | /*
314 | * Lists the destinations that an application can specify for a download.
315 | */
316 |
317 | /**
318 | * This download will be saved to the external storage. This is the
319 | * default behavior, and should be used for any file that the user
320 | * can freely access, copy, delete. Even with that destination,
321 | * unencrypted DRM files are saved in secure internal storage.
322 | * Downloads to the external destination only write files for which
323 | * there is a registered handler. The resulting files are accessible
324 | * by filename to all applications.
325 | * @hide
326 | */
327 | public static final int DESTINATION_EXTERNAL = 0;
328 |
329 | /**
330 | * This download will be saved to the download manager's private
331 | * partition. This is the behavior used by applications that want to
332 | * download private files that are used and deleted soon after they
333 | * get downloaded. All file types are allowed, and only the initiating
334 | * application can access the file (indirectly through a content
335 | * provider). This requires the
336 | * android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED permission.
337 | * @hide
338 | */
339 | public static final int DESTINATION_CACHE_PARTITION = 1;
340 |
341 | /**
342 | * This download will be saved to the download manager's private
343 | * partition and will be purged as necessary to make space. This is
344 | * for private files (similar to CACHE_PARTITION) that aren't deleted
345 | * immediately after they are used, and are kept around by the download
346 | * manager as long as space is available.
347 | * @hide
348 | */
349 | public static final int DESTINATION_CACHE_PARTITION_PURGEABLE = 2;
350 |
351 | /**
352 | * This download will be saved to the download manager's private
353 | * partition, as with DESTINATION_CACHE_PARTITION, but the download
354 | * will not proceed if the user is on a roaming data connection.
355 | * @hide
356 | */
357 | public static final int DESTINATION_CACHE_PARTITION_NOROAMING = 3;
358 |
359 | /**
360 | * This download is allowed to run.
361 | * @hide
362 | */
363 | public static final int CONTROL_RUN = 0;
364 |
365 | /**
366 | * This download must pause at the first opportunity.
367 | * @hide
368 | */
369 | public static final int CONTROL_PAUSED = 1;
370 |
371 | /*
372 | * Lists the states that the download manager can set on a download
373 | * to notify applications of the download progress.
374 | * The codes follow the HTTP families:
375 | * 1xx: informational
376 | * 2xx: success
377 | * 3xx: redirects (not used by the download manager)
378 | * 4xx: client errors
379 | * 5xx: server errors
380 | */
381 |
382 | /**
383 | * Returns whether the status is informational (i.e. 1xx).
384 | * @hide
385 | */
386 | public static boolean isStatusInformational(int status) {
387 | return (status >= 100 && status < 200);
388 | }
389 |
390 | /**
391 | * Returns whether the status is a success (i.e. 2xx).
392 | * @hide
393 | */
394 | public static boolean isStatusSuccess(int status) {
395 | return (status >= 200 && status < 300);
396 | }
397 |
398 | /**
399 | * Returns whether the status is an error (i.e. 4xx or 5xx).
400 | * @hide
401 | */
402 | public static boolean isStatusError(int status) {
403 | return (status >= 400 && status < 600);
404 | }
405 |
406 | /**
407 | * Returns whether the status is a client error (i.e. 4xx).
408 | * @hide
409 | */
410 | public static boolean isStatusClientError(int status) {
411 | return (status >= 400 && status < 500);
412 | }
413 |
414 | /**
415 | * Returns whether the status is a server error (i.e. 5xx).
416 | * @hide
417 | */
418 | public static boolean isStatusServerError(int status) {
419 | return (status >= 500 && status < 600);
420 | }
421 |
422 | /**
423 | * Returns whether the download has completed (either with success or
424 | * error).
425 | * @hide
426 | */
427 | public static boolean isStatusCompleted(int status) {
428 | return (status >= 200 && status < 300) || (status >= 400 && status < 600);
429 | }
430 |
431 | /**
432 | * This download hasn't stated yet
433 | * @hide
434 | */
435 | public static final int STATUS_PENDING = 190;
436 |
437 | /**
438 | * This download has started
439 | * @hide
440 | */
441 | public static final int STATUS_RUNNING = 192;
442 |
443 | /**
444 | * This download has successfully completed.
445 | * Warning: there might be other status values that indicate success
446 | * in the future.
447 | * Use isSucccess() to capture the entire category.
448 | * @hide
449 | */
450 | public static final int STATUS_SUCCESS = 200;
451 |
452 | /**
453 | * This request couldn't be parsed. This is also used when processing
454 | * requests with unknown/unsupported URI schemes.
455 | * @hide
456 | */
457 | public static final int STATUS_BAD_REQUEST = 400;
458 |
459 | /**
460 | * This download can't be performed because the content type cannot be
461 | * handled.
462 | * @hide
463 | */
464 | public static final int STATUS_NOT_ACCEPTABLE = 406;
465 |
466 | /**
467 | * This download cannot be performed because the length cannot be
468 | * determined accurately. This is the code for the HTTP error "Length
469 | * Required", which is typically used when making requests that require
470 | * a content length but don't have one, and it is also used in the
471 | * client when a response is received whose length cannot be determined
472 | * accurately (therefore making it impossible to know when a download
473 | * completes).
474 | * @hide
475 | */
476 | public static final int STATUS_LENGTH_REQUIRED = 411;
477 |
478 | /**
479 | * This download was interrupted and cannot be resumed.
480 | * This is the code for the HTTP error "Precondition Failed", and it is
481 | * also used in situations where the client doesn't have an ETag at all.
482 | * @hide
483 | */
484 | public static final int STATUS_PRECONDITION_FAILED = 412;
485 |
486 | /**
487 | * This download was canceled
488 | * @hide
489 | */
490 | public static final int STATUS_CANCELED = 490;
491 |
492 | /**
493 | * This download has completed with an error.
494 | * Warning: there will be other status values that indicate errors in
495 | * the future. Use isStatusError() to capture the entire category.
496 | * @hide
497 | */
498 | public static final int STATUS_UNKNOWN_ERROR = 491;
499 |
500 | /**
501 | * This download couldn't be completed because of a storage issue.
502 | * Typically, that's because the filesystem is missing or full.
503 | * Use the more specific {@link #STATUS_INSUFFICIENT_SPACE_ERROR}
504 | * and {@link #STATUS_DEVICE_NOT_FOUND_ERROR} when appropriate.
505 | * @hide
506 | */
507 | public static final int STATUS_FILE_ERROR = 492;
508 |
509 | /**
510 | * This download couldn't be completed because of an HTTP
511 | * redirect response that the download manager couldn't
512 | * handle.
513 | * @hide
514 | */
515 | public static final int STATUS_UNHANDLED_REDIRECT = 493;
516 |
517 | /**
518 | * This download couldn't be completed because of an
519 | * unspecified unhandled HTTP code.
520 | * @hide
521 | */
522 | public static final int STATUS_UNHANDLED_HTTP_CODE = 494;
523 |
524 | /**
525 | * This download couldn't be completed because of an
526 | * error receiving or processing data at the HTTP level.
527 | * @hide
528 | */
529 | public static final int STATUS_HTTP_DATA_ERROR = 495;
530 |
531 | /**
532 | * This download couldn't be completed because of an
533 | * HttpException while setting up the request.
534 | * @hide
535 | */
536 | public static final int STATUS_HTTP_EXCEPTION = 496;
537 |
538 | /**
539 | * This download couldn't be completed because there were
540 | * too many redirects.
541 | * @hide
542 | */
543 | public static final int STATUS_TOO_MANY_REDIRECTS = 497;
544 |
545 | /**
546 | * This download couldn't be completed due to insufficient storage
547 | * space. Typically, this is because the SD card is full.
548 | * @hide
549 | */
550 | public static final int STATUS_INSUFFICIENT_SPACE_ERROR = 498;
551 |
552 | /**
553 | * This download couldn't be completed because no external storage
554 | * device was found. Typically, this is because the SD card is not
555 | * mounted.
556 | * @hide
557 | */
558 | public static final int STATUS_DEVICE_NOT_FOUND_ERROR = 499;
559 |
560 | /**
561 | * This download is visible but only shows in the notifications
562 | * while it's in progress.
563 | * @hide
564 | */
565 | public static final int VISIBILITY_VISIBLE = 0;
566 |
567 | /**
568 | * This download is visible and shows in the notifications while
569 | * in progress and after completion.
570 | * @hide
571 | */
572 | public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1;
573 |
574 | /**
575 | * This download doesn't show in the UI or in the notifications.
576 | * @hide
577 | */
578 | public static final int VISIBILITY_HIDDEN = 2;
579 |
580 | /**
581 | * Implementation details
582 | *
583 | * Exposes constants used to interact with the download manager's
584 | * content provider.
585 | * The constants URI ... STATUS are the names of columns in the downloads table.
586 | *
587 | * @hide
588 | */
589 | public static final class Impl implements BaseColumns {
590 | private Impl() {}
591 |
592 | /**
593 | * The permission to access the download manager
594 | */
595 | public static final String PERMISSION_ACCESS = "android.permission.ACCESS_DOWNLOAD_MANAGER";
596 |
597 | /**
598 | * The permission to access the download manager's advanced functions
599 | */
600 | public static final String PERMISSION_ACCESS_ADVANCED =
601 | "android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED";
602 |
603 | /**
604 | * The permission to access the all the downloads in the manager.
605 | */
606 | public static final String PERMISSION_ACCESS_ALL =
607 | "android.permission.ACCESS_ALL_DOWNLOADS";
608 |
609 | /**
610 | * The permission to directly access the download manager's cache
611 | * directory
612 | */
613 | public static final String PERMISSION_CACHE = "android.permission.ACCESS_CACHE_FILESYSTEM";
614 |
615 | /**
616 | * The permission to send broadcasts on download completion
617 | */
618 | public static final String PERMISSION_SEND_INTENTS =
619 | "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS";
620 |
621 | /**
622 | * The permission to download files to the cache partition that won't be automatically
623 | * purged when space is needed.
624 | */
625 | public static final String PERMISSION_CACHE_NON_PURGEABLE =
626 | "android.permission.DOWNLOAD_CACHE_NON_PURGEABLE";
627 |
628 | /**
629 | * The permission to download files without any system notification being shown.
630 | */
631 | public static final String PERMISSION_NO_NOTIFICATION =
632 | "android.permission.DOWNLOAD_WITHOUT_NOTIFICATION";
633 |
634 | /**
635 | * The content:// URI to access downloads owned by the caller's UID.
636 | */
637 | public static final Uri CONTENT_URI =
638 | Uri.parse("content://downloads/my_downloads");
639 |
640 | /**
641 | * The content URI for accessing all downloads across all UIDs (requires the
642 | * ACCESS_ALL_DOWNLOADS permission).
643 | */
644 | public static final Uri ALL_DOWNLOADS_CONTENT_URI =
645 | Uri.parse("content://downloads/all_downloads");
646 |
647 | /**
648 | * Broadcast Action: this is sent by the download manager to the app
649 | * that had initiated a download when that download completes. The
650 | * download's content: uri is specified in the intent's data.
651 | */
652 | public static final String ACTION_DOWNLOAD_COMPLETED =
653 | "android.intent.action.DOWNLOAD_COMPLETED";
654 |
655 | /**
656 | * Broadcast Action: this is sent by the download manager to the app
657 | * that had initiated a download when the user selects the notification
658 | * associated with that download. The download's content: uri is specified
659 | * in the intent's data if the click is associated with a single download,
660 | * or Downloads.CONTENT_URI if the notification is associated with
661 | * multiple downloads.
662 | * Note: this is not currently sent for downloads that have completed
663 | * successfully.
664 | */
665 | public static final String ACTION_NOTIFICATION_CLICKED =
666 | "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
667 |
668 | /**
669 | * The name of the column containing the URI of the data being downloaded.
670 | *
Type: TEXT
671 | *
Owner can Init/Read
672 | */
673 | public static final String COLUMN_URI = "uri";
674 |
675 | /**
676 | * The name of the column containing application-specific data.
677 | *
Type: TEXT
678 | *
Owner can Init/Read/Write
679 | */
680 | public static final String COLUMN_APP_DATA = "entity";
681 |
682 | /**
683 | * The name of the column containing the flags that indicates whether
684 | * the initiating application is capable of verifying the integrity of
685 | * the downloaded file. When this flag is set, the download manager
686 | * performs downloads and reports success even in some situations where
687 | * it can't guarantee that the download has completed (e.g. when doing
688 | * a byte-range request without an ETag, or when it can't determine
689 | * whether a download fully completed).
690 | *
Type: BOOLEAN
691 | *
Owner can Init
692 | */
693 | public static final String COLUMN_NO_INTEGRITY = "no_integrity";
694 |
695 | /**
696 | * The name of the column containing the filename that the initiating
697 | * application recommends. When possible, the download manager will attempt
698 | * to use this filename, or a variation, as the actual name for the file.
699 | *
Type: TEXT
700 | *
Owner can Init
701 | */
702 | public static final String COLUMN_FILE_NAME_HINT = "hint";
703 |
704 | /**
705 | * The name of the column containing the filename where the downloaded data
706 | * was actually stored.
707 | *
Type: TEXT
708 | *
Owner can Read
709 | */
710 | public static final String _DATA = "_data";
711 |
712 | /**
713 | * The name of the column containing the MIME type of the downloaded data.
714 | *
Type: TEXT
715 | *
Owner can Init/Read
716 | */
717 | public static final String COLUMN_MIME_TYPE = "mimetype";
718 |
719 | /**
720 | * The name of the column containing the flag that controls the destination
721 | * of the download. See the DESTINATION_* constants for a list of legal values.
722 | *
Type: INTEGER
723 | *
Owner can Init
724 | */
725 | public static final String COLUMN_DESTINATION = "destination";
726 |
727 | /**
728 | * The name of the column containing the flags that controls whether the
729 | * download is displayed by the UI. See the VISIBILITY_* constants for
730 | * a list of legal values.
731 | *
Type: INTEGER
732 | *
Owner can Init/Read/Write
733 | */
734 | public static final String COLUMN_VISIBILITY = "visibility";
735 |
736 | /**
737 | * The name of the column containing the current control state of the download.
738 | * Applications can write to this to control (pause/resume) the download.
739 | * the CONTROL_* constants for a list of legal values.
740 | *
Type: INTEGER
741 | *
Owner can Read
742 | */
743 | public static final String COLUMN_CONTROL = "control";
744 |
745 | /**
746 | * The name of the column containing the current status of the download.
747 | * Applications can read this to follow the progress of each download. See
748 | * the STATUS_* constants for a list of legal values.
749 | *
Type: INTEGER
750 | *
Owner can Read
751 | */
752 | public static final String COLUMN_STATUS = "status";
753 |
754 | /**
755 | * The name of the column containing the date at which some interesting
756 | * status changed in the download. Stored as a System.currentTimeMillis()
757 | * value.
758 | *
Type: BIGINT
759 | *
Owner can Read
760 | */
761 | public static final String COLUMN_LAST_MODIFICATION = "lastmod";
762 |
763 | /**
764 | * The name of the column containing the package name of the application
765 | * that initiating the download. The download manager will send
766 | * notifications to a component in this package when the download completes.
767 | *
Type: TEXT
768 | *
Owner can Init/Read
769 | */
770 | public static final String COLUMN_NOTIFICATION_PACKAGE = "notificationpackage";
771 |
772 | /**
773 | * The name of the column containing the component name of the class that
774 | * will receive notifications associated with the download. The
775 | * package/class combination is passed to
776 | * Intent.setClassName(String,String).
777 | *
Type: TEXT
778 | *
Owner can Init/Read
779 | */
780 | public static final String COLUMN_NOTIFICATION_CLASS = "notificationclass";
781 |
782 | /**
783 | * If extras are specified when requesting a download they will be provided in the intent that
784 | * is sent to the specified class and package when a download has finished.
785 | *
Type: TEXT
786 | *
Owner can Init
787 | */
788 | public static final String COLUMN_NOTIFICATION_EXTRAS = "notificationextras";
789 |
790 | /**
791 | * The name of the column contain the values of the cookie to be used for
792 | * the download. This is used directly as the value for the Cookie: HTTP
793 | * header that gets sent with the request.
794 | *
Type: TEXT
795 | *
Owner can Init
796 | */
797 | public static final String COLUMN_COOKIE_DATA = "cookiedata";
798 |
799 | /**
800 | * The name of the column containing the user agent that the initiating
801 | * application wants the download manager to use for this download.
802 | *
Type: TEXT
803 | *
Owner can Init
804 | */
805 | public static final String COLUMN_USER_AGENT = "useragent";
806 |
807 | /**
808 | * The name of the column containing the referer (sic) that the initiating
809 | * application wants the download manager to use for this download.
810 | *
Type: TEXT
811 | *
Owner can Init
812 | */
813 | public static final String COLUMN_REFERER = "referer";
814 |
815 | /**
816 | * The name of the column containing the total size of the file being
817 | * downloaded.
818 | *
Type: INTEGER
819 | *
Owner can Read
820 | */
821 | public static final String COLUMN_TOTAL_BYTES = "total_bytes";
822 |
823 | /**
824 | * The name of the column containing the size of the part of the file that
825 | * has been downloaded so far.
826 | *
Type: INTEGER
827 | *
Owner can Read
828 | */
829 | public static final String COLUMN_CURRENT_BYTES = "current_bytes";
830 |
831 | /**
832 | * The name of the column where the initiating application can provide the
833 | * UID of another application that is allowed to access this download. If
834 | * multiple applications share the same UID, all those applications will be
835 | * allowed to access this download. This column can be updated after the
836 | * download is initiated. This requires the permission
837 | * android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED.
838 | *
Type: INTEGER
839 | *
Owner can Init
840 | */
841 | public static final String COLUMN_OTHER_UID = "otheruid";
842 |
843 | /**
844 | * The name of the column where the initiating application can provided the
845 | * title of this download. The title will be displayed ito the user in the
846 | * list of downloads.
847 | *
Type: TEXT
848 | *
Owner can Init/Read/Write
849 | */
850 | public static final String COLUMN_TITLE = "title";
851 |
852 | /**
853 | * The name of the column where the initiating application can provide the
854 | * description of this download. The description will be displayed to the
855 | * user in the list of downloads.
856 | *
Type: TEXT
857 | *
Owner can Init/Read/Write
858 | */
859 | public static final String COLUMN_DESCRIPTION = "description";
860 |
861 | /**
862 | * The name of the column indicating whether the download was requesting through the public
863 | * API. This controls some differences in behavior.
864 | *
Type: BOOLEAN
865 | *
Owner can Init/Read
866 | */
867 | public static final String COLUMN_IS_PUBLIC_API = "is_public_api";
868 |
869 | /**
870 | * The name of the column indicating whether roaming connections can be used. This is only
871 | * used for public API downloads.
872 | *
Type: BOOLEAN
873 | *
Owner can Init/Read
874 | */
875 | public static final String COLUMN_ALLOW_ROAMING = "allow_roaming";
876 |
877 | /**
878 | * The name of the column holding a bitmask of allowed network types. This is only used for
879 | * public API downloads.
880 | *
Type: INTEGER
881 | *
Owner can Init/Read
882 | */
883 | public static final String COLUMN_ALLOWED_NETWORK_TYPES = "allowed_network_types";
884 |
885 | /**
886 | * Whether or not this download should be displayed in the system's Downloads UI. Defaults
887 | * to true.
888 | *
Type: INTEGER
889 | *
Owner can Init/Read
890 | */
891 | public static final String COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI = "is_visible_in_downloads_ui";
892 |
893 | /**
894 | * If true, the user has confirmed that this download can proceed over the mobile network
895 | * even though it exceeds the recommended maximum size.
896 | *
Type: BOOLEAN
897 | */
898 | public static final String COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT =
899 | "bypass_recommended_size_limit";
900 |
901 | /**
902 | * Set to true if this download is deleted. It is completely removed from the database
903 | * when MediaProvider database also deletes the metadata asociated with this downloaded file.
904 | *
Type: BOOLEAN
905 | *
Owner can Read
906 | */
907 | public static final String COLUMN_DELETED = "deleted";
908 |
909 | /**
910 | * The URI to the corresponding entry in MediaProvider for this downloaded entry. It is
911 | * used to delete the entries from MediaProvider database when it is deleted from the
912 | * downloaded list.
913 | *
Type: TEXT
914 | *
Owner can Read
915 | */
916 | public static final String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
917 |
918 | /*
919 | * Lists the destinations that an application can specify for a download.
920 | */
921 |
922 | /**
923 | * This download will be saved to the external storage. This is the
924 | * default behavior, and should be used for any file that the user
925 | * can freely access, copy, delete. Even with that destination,
926 | * unencrypted DRM files are saved in secure internal storage.
927 | * Downloads to the external destination only write files for which
928 | * there is a registered handler. The resulting files are accessible
929 | * by filename to all applications.
930 | */
931 | public static final int DESTINATION_EXTERNAL = 0;
932 |
933 | /**
934 | * This download will be saved to the download manager's private
935 | * partition. This is the behavior used by applications that want to
936 | * download private files that are used and deleted soon after they
937 | * get downloaded. All file types are allowed, and only the initiating
938 | * application can access the file (indirectly through a content
939 | * provider). This requires the
940 | * android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED permission.
941 | */
942 | public static final int DESTINATION_CACHE_PARTITION = 1;
943 |
944 | /**
945 | * This download will be saved to the download manager's private
946 | * partition and will be purged as necessary to make space. This is
947 | * for private files (similar to CACHE_PARTITION) that aren't deleted
948 | * immediately after they are used, and are kept around by the download
949 | * manager as long as space is available.
950 | */
951 | public static final int DESTINATION_CACHE_PARTITION_PURGEABLE = 2;
952 |
953 | /**
954 | * This download will be saved to the download manager's private
955 | * partition, as with DESTINATION_CACHE_PARTITION, but the download
956 | * will not proceed if the user is on a roaming data connection.
957 | */
958 | public static final int DESTINATION_CACHE_PARTITION_NOROAMING = 3;
959 |
960 | /**
961 | * This download will be saved to the location given by the file URI in
962 | * {@link #COLUMN_FILE_NAME_HINT}.
963 | */
964 | public static final int DESTINATION_FILE_URI = 4;
965 |
966 | /**
967 | * This download is allowed to run.
968 | */
969 | public static final int CONTROL_RUN = 0;
970 |
971 | /**
972 | * This download must pause at the first opportunity.
973 | */
974 | public static final int CONTROL_PAUSED = 1;
975 |
976 | /*
977 | * Lists the states that the download manager can set on a download
978 | * to notify applications of the download progress.
979 | * The codes follow the HTTP families:
980 | * 1xx: informational
981 | * 2xx: success
982 | * 3xx: redirects (not used by the download manager)
983 | * 4xx: client errors
984 | * 5xx: server errors
985 | */
986 |
987 | /**
988 | * Returns whether the status is informational (i.e. 1xx).
989 | */
990 | public static boolean isStatusInformational(int status) {
991 | return (status >= 100 && status < 200);
992 | }
993 |
994 | /**
995 | * Returns whether the status is a success (i.e. 2xx).
996 | */
997 | public static boolean isStatusSuccess(int status) {
998 | return (status >= 200 && status < 300);
999 | }
1000 |
1001 | /**
1002 | * Returns whether the status is an error (i.e. 4xx or 5xx).
1003 | */
1004 | public static boolean isStatusError(int status) {
1005 | return (status >= 400 && status < 600);
1006 | }
1007 |
1008 | /**
1009 | * Returns whether the status is a client error (i.e. 4xx).
1010 | */
1011 | public static boolean isStatusClientError(int status) {
1012 | return (status >= 400 && status < 500);
1013 | }
1014 |
1015 | /**
1016 | * Returns whether the status is a server error (i.e. 5xx).
1017 | */
1018 | public static boolean isStatusServerError(int status) {
1019 | return (status >= 500 && status < 600);
1020 | }
1021 |
1022 | /**
1023 | * Returns whether the download has completed (either with success or
1024 | * error).
1025 | */
1026 | public static boolean isStatusCompleted(int status) {
1027 | return (status >= 200 && status < 300) || (status >= 400 && status < 600);
1028 | }
1029 |
1030 | /**
1031 | * This download hasn't stated yet
1032 | */
1033 | public static final int STATUS_PENDING = 190;
1034 |
1035 | /**
1036 | * This download has started
1037 | */
1038 | public static final int STATUS_RUNNING = 192;
1039 |
1040 | /**
1041 | * This download has been paused by the owning app.
1042 | */
1043 | public static final int STATUS_PAUSED_BY_APP = 193;
1044 |
1045 | /**
1046 | * This download encountered some network error and is waiting before retrying the request.
1047 | */
1048 | public static final int STATUS_WAITING_TO_RETRY = 194;
1049 |
1050 | /**
1051 | * This download is waiting for network connectivity to proceed.
1052 | */
1053 | public static final int STATUS_WAITING_FOR_NETWORK = 195;
1054 |
1055 | /**
1056 | * This download exceeded a size limit for mobile networks and is waiting for a Wi-Fi
1057 | * connection to proceed.
1058 | */
1059 | public static final int STATUS_QUEUED_FOR_WIFI = 196;
1060 |
1061 | /**
1062 | * This download has successfully completed.
1063 | * Warning: there might be other status values that indicate success
1064 | * in the future.
1065 | * Use isSucccess() to capture the entire category.
1066 | */
1067 | public static final int STATUS_SUCCESS = 200;
1068 |
1069 | /**
1070 | * This request couldn't be parsed. This is also used when processing
1071 | * requests with unknown/unsupported URI schemes.
1072 | */
1073 | public static final int STATUS_BAD_REQUEST = 400;
1074 |
1075 | /**
1076 | * This download can't be performed because the content type cannot be
1077 | * handled.
1078 | */
1079 | public static final int STATUS_NOT_ACCEPTABLE = 406;
1080 |
1081 | /**
1082 | * This download cannot be performed because the length cannot be
1083 | * determined accurately. This is the code for the HTTP error "Length
1084 | * Required", which is typically used when making requests that require
1085 | * a content length but don't have one, and it is also used in the
1086 | * client when a response is received whose length cannot be determined
1087 | * accurately (therefore making it impossible to know when a download
1088 | * completes).
1089 | */
1090 | public static final int STATUS_LENGTH_REQUIRED = 411;
1091 |
1092 | /**
1093 | * This download was interrupted and cannot be resumed.
1094 | * This is the code for the HTTP error "Precondition Failed", and it is
1095 | * also used in situations where the client doesn't have an ETag at all.
1096 | */
1097 | public static final int STATUS_PRECONDITION_FAILED = 412;
1098 |
1099 | /**
1100 | * The lowest-valued error status that is not an actual HTTP status code.
1101 | */
1102 | public static final int MIN_ARTIFICIAL_ERROR_STATUS = 488;
1103 |
1104 | /**
1105 | * The requested destination file already exists.
1106 | */
1107 | public static final int STATUS_FILE_ALREADY_EXISTS_ERROR = 488;
1108 |
1109 | /**
1110 | * Some possibly transient error occurred, but we can't resume the download.
1111 | */
1112 | public static final int STATUS_CANNOT_RESUME = 489;
1113 |
1114 | /**
1115 | * This download was canceled
1116 | */
1117 | public static final int STATUS_CANCELED = 490;
1118 |
1119 | /**
1120 | * This download has completed with an error.
1121 | * Warning: there will be other status values that indicate errors in
1122 | * the future. Use isStatusError() to capture the entire category.
1123 | */
1124 | public static final int STATUS_UNKNOWN_ERROR = 491;
1125 |
1126 | /**
1127 | * This download couldn't be completed because of a storage issue.
1128 | * Typically, that's because the filesystem is missing or full.
1129 | * Use the more specific {@link #STATUS_INSUFFICIENT_SPACE_ERROR}
1130 | * and {@link #STATUS_DEVICE_NOT_FOUND_ERROR} when appropriate.
1131 | */
1132 | public static final int STATUS_FILE_ERROR = 492;
1133 |
1134 | /**
1135 | * This download couldn't be completed because of an HTTP
1136 | * redirect response that the download manager couldn't
1137 | * handle.
1138 | */
1139 | public static final int STATUS_UNHANDLED_REDIRECT = 493;
1140 |
1141 | /**
1142 | * This download couldn't be completed because of an
1143 | * unspecified unhandled HTTP code.
1144 | */
1145 | public static final int STATUS_UNHANDLED_HTTP_CODE = 494;
1146 |
1147 | /**
1148 | * This download couldn't be completed because of an
1149 | * error receiving or processing data at the HTTP level.
1150 | */
1151 | public static final int STATUS_HTTP_DATA_ERROR = 495;
1152 |
1153 | /**
1154 | * This download couldn't be completed because of an
1155 | * HttpException while setting up the request.
1156 | */
1157 | public static final int STATUS_HTTP_EXCEPTION = 496;
1158 |
1159 | /**
1160 | * This download couldn't be completed because there were
1161 | * too many redirects.
1162 | */
1163 | public static final int STATUS_TOO_MANY_REDIRECTS = 497;
1164 |
1165 | /**
1166 | * This download couldn't be completed due to insufficient storage
1167 | * space. Typically, this is because the SD card is full.
1168 | */
1169 | public static final int STATUS_INSUFFICIENT_SPACE_ERROR = 498;
1170 |
1171 | /**
1172 | * This download couldn't be completed because no external storage
1173 | * device was found. Typically, this is because the SD card is not
1174 | * mounted.
1175 | */
1176 | public static final int STATUS_DEVICE_NOT_FOUND_ERROR = 499;
1177 |
1178 | /**
1179 | * This download is visible but only shows in the notifications
1180 | * while it's in progress.
1181 | */
1182 | public static final int VISIBILITY_VISIBLE = 0;
1183 |
1184 | /**
1185 | * This download is visible and shows in the notifications while
1186 | * in progress and after completion.
1187 | */
1188 | public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1;
1189 |
1190 | /**
1191 | * This download doesn't show in the UI or in the notifications.
1192 | */
1193 | public static final int VISIBILITY_HIDDEN = 2;
1194 |
1195 | /**
1196 | * Constants related to HTTP request headers associated with each download.
1197 | */
1198 | public static class RequestHeaders {
1199 | public static final String HEADERS_DB_TABLE = "request_headers";
1200 | public static final String COLUMN_DOWNLOAD_ID = "download_id";
1201 | public static final String COLUMN_HEADER = "header";
1202 | public static final String COLUMN_VALUE = "value";
1203 |
1204 | /**
1205 | * Path segment to add to a download URI to retrieve request headers
1206 | */
1207 | public static final String URI_SEGMENT = "headers";
1208 |
1209 | /**
1210 | * Prefix for ContentValues keys that contain HTTP header lines, to be passed to
1211 | * DownloadProvider.insert().
1212 | */
1213 | public static final String INSERT_KEY_PREFIX = "http_header_";
1214 | }
1215 | }
1216 | }
--------------------------------------------------------------------------------