如何请求Android下载管理器同时下载多个文件。我也想知道每个文件的下载状态。
请求第一个。
然后,请求第二个。
然后,请求第三个。
根据需要继续。
他们是否"同时"下载不是你关心的问题,你也无法控制。他们会在DownloadManager
决定下载时下载,这可能是同时的,也可能不是。
1. Register listener for download complete
IntentFilter intentFilter = new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE);
registerReceiver(downloadReceiver, intentFilter);
2.Make request
Uri downloadUri = Uri.parse(entry.getValue());
DownloadManager.Request request = new DownloadManager.Request(
downloadUri);
request.setDestinationUri(path_to _file_store)));
downloadManager.enqueue(request);
3.Check status in listener
private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context arg0, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
long downloadId = intent.getLongExtra(
DownloadManager.EXTRA_DOWNLOAD_ID, 0);
System.out.println("download id=" + downloadId);
CheckDwnloadStatus(downloadId);
}
}
};
private void CheckDwnloadStatus(long id) {
// TODO Auto-generated method stub
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(id);
Cursor cursor = downloadManager.query(query);
if (cursor.moveToFirst()) {
int columnIndex = cursor
.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = cursor.getInt(columnIndex);
int columnReason = cursor
.getColumnIndex(DownloadManager.COLUMN_REASON);
int reason = cursor.getInt(columnReason);
switch (status) {
case DownloadManager.STATUS_FAILED:
String failedReason = "";
switch (reason) {
case DownloadManager.ERROR_CANNOT_RESUME:
failedReason = "ERROR_CANNOT_RESUME";
break;
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
failedReason = "ERROR_DEVICE_NOT_FOUND";
break;
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
failedReason = "ERROR_FILE_ALREADY_EXISTS";
break;
case DownloadManager.ERROR_FILE_ERROR:
failedReason = "ERROR_FILE_ERROR";
break;
case DownloadManager.ERROR_HTTP_DATA_ERROR:
failedReason = "ERROR_HTTP_DATA_ERROR";
break;
case DownloadManager.ERROR_INSUFFICIENT_SPACE:
failedReason = "ERROR_INSUFFICIENT_SPACE";
break;
case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
failedReason = "ERROR_TOO_MANY_REDIRECTS";
break;
case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
failedReason = "ERROR_UNHANDLED_HTTP_CODE";
break;
case DownloadManager.ERROR_UNKNOWN:
failedReason = "ERROR_UNKNOWN";
break;
}
Toast.makeText(this, "FAILED: " + failedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PAUSED:
String pausedReason = "";
switch (reason) {
case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
pausedReason = "PAUSED_QUEUED_FOR_WIFI";
break;
case DownloadManager.PAUSED_UNKNOWN:
pausedReason = "PAUSED_UNKNOWN";
break;
case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
pausedReason = "PAUSED_WAITING_FOR_NETWORK";
break;
case DownloadManager.PAUSED_WAITING_TO_RETRY:
pausedReason = "PAUSED_WAITING_TO_RETRY";
break;
}
Toast.makeText(this, "PAUSED: " + pausedReason,
Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_PENDING:
Toast.makeText(this, "PENDING", Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_RUNNING:
Toast.makeText(this, "RUNNING", Toast.LENGTH_LONG).show();
break;
case DownloadManager.STATUS_SUCCESSFUL:
caluclateLoadingData();
// Toast.makeText(this, "SUCCESSFUL", Toast.LENGTH_LONG).show();
// GetFile();
break;
}
}
}
public final class Downloads {
/**
* @hide
*/
private Downloads() {}
/**
* The permission to access the download manager
* @hide .
*/
public static final String PERMISSION_ACCESS = "android.permission.ACCESS_DOWNLOAD_MANAGER";
/**
* The permission to access the download manager's advanced functions
* @hide
*/
public static final String PERMISSION_ACCESS_ADVANCED =
"android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED";
/**
* The permission to directly access the download manager's cache directory
* @hide
*/
public static final String PERMISSION_CACHE = "android.permission.ACCESS_CACHE_FILESYSTEM";
/**
* The permission to send broadcasts on download completion
* @hide
*/
public static final String PERMISSION_SEND_INTENTS =
"android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS";
/**
* The content:// URI for the data table in the provider
* @hide
*/
public static final Uri CONTENT_URI =
Uri.parse("content://downloads/my_downloads");
/**
* Broadcast Action: this is sent by the download manager to the app
* that had initiated a download when that download completes. The
* download's content: uri is specified in the intent's data.
* @hide
*/
public static final String ACTION_DOWNLOAD_COMPLETED =
"android.intent.action.DOWNLOAD_COMPLETED";
/**
* Broadcast Action: this is sent by the download manager to the app
* that had initiated a download when the user selects the notification
* associated with that download. The download's content: uri is specified
* in the intent's data if the click is associated with a single download,
* or Downloads.CONTENT_URI if the notification is associated with
* multiple downloads.
* Note: this is not currently sent for downloads that have completed
* successfully.
* @hide
*/
public static final String ACTION_NOTIFICATION_CLICKED =
"android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
/**
* The name of the column containing the URI of the data being downloaded.
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
* @hide
*/
public static final String COLUMN_URI = "uri";
public static final String COLUMN_APP_DATA = "entity";
public static final String COLUMN_NO_INTEGRITY = "no_integrity";
public static final String COLUMN_FILE_NAME_HINT = "hint";
public static final String _DATA = "_data";
public static final String COLUMN_MIME_TYPE = "mimetype";
public static final String COLUMN_DESTINATION = "destination";
public static final String COLUMN_VISIBILITY = "visibility";
public static final String COLUMN_CONTROL = "control";
public static final String COLUMN_STATUS = "status";
/**
* The name of the column containing the date at which some interesting
* status changed in the download. Stored as a System.currentTimeMillis()
* value.
* <P>Type: BIGINT</P>
* <P>Owner can Read</P>
* @hide
*/
public static final String COLUMN_LAST_MODIFICATION = "lastmod";
/**
* The name of the column containing the package name of the application
* that initiating the download. The download manager will send
* notifications to a component in this package when the download completes.
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
* @hide
*/
public static final String COLUMN_NOTIFICATION_PACKAGE = "notificationpackage";
public static final String COLUMN_NOTIFICATION_CLASS = "notificationclass";
public static final String COLUMN_NOTIFICATION_EXTRAS = "notificationextras";
public static final String COLUMN_COOKIE_DATA = "cookiedata";
public static final String COLUMN_USER_AGENT = "useragent";
public static final String COLUMN_REFERER = "referer";
public static final String COLUMN_TOTAL_BYTES = "total_bytes";
public static final String COLUMN_CURRENT_BYTES = "current_bytes";
public static final String COLUMN_OTHER_UID = "otheruid";
public static final String COLUMN_TITLE = "title";
public static final String COLUMN_DESCRIPTION = "description";
public static final String COLUMN_DELETED = "deleted";
public static final int DESTINATION_EXTERNAL = 0;
public static final int DESTINATION_CACHE_PARTITION = 1;
public static final int DESTINATION_CACHE_PARTITION_PURGEABLE = 2;
public static final int DESTINATION_CACHE_PARTITION_NOROAMING = 3;
public static final int CONTROL_RUN = 0;
public static final int CONTROL_PAUSED = 1;
/**
* Returns whether the status is informational (i.e. 1xx).
* @hide
*/
public static boolean isStatusInformational(int status) {
return (status >= 100 && status < 200);
}
public static boolean isStatusSuccess(int status) {
return (status >= 200 && status < 300);
}
public static boolean isStatusError(int status) {
return (status >= 400 && status < 600);
}
public static boolean isStatusClientError(int status) {
return (status >= 400 && status < 500);
}
public static boolean isStatusServerError(int status) {
return (status >= 500 && status < 600);
}
public static boolean isStatusCompleted(int status) {
return (status >= 200 && status < 300) || (status >= 400 && status < 600);
}
public static final int STATUS_PENDING = 190;
public static final int STATUS_RUNNING = 192;
public static final int STATUS_SUCCESS = 200;
public static final int STATUS_BAD_REQUEST = 400;
public static final int STATUS_NOT_ACCEPTABLE = 406;
public static final int STATUS_LENGTH_REQUIRED = 411;
public static final int STATUS_PRECONDITION_FAILED = 412;
public static final int STATUS_CANCELED = 490;
public static final int STATUS_UNKNOWN_ERROR = 491;
public static final int STATUS_FILE_ERROR = 492;
public static final int STATUS_UNHANDLED_REDIRECT = 493;
public static final int STATUS_UNHANDLED_HTTP_CODE = 494;
public static final int STATUS_HTTP_DATA_ERROR = 495;
public static final int STATUS_HTTP_EXCEPTION = 496;
public static final int STATUS_TOO_MANY_REDIRECTS = 497;
public static final int STATUS_INSUFFICIENT_SPACE_ERROR = 498;
public static final int STATUS_DEVICE_NOT_FOUND_ERROR = 499;
public static final int VISIBILITY_VISIBLE = 0;
public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1;
public static final int VISIBILITY_HIDDEN = 2;
public static final class Impl implements BaseColumns {
private Impl() {}
/**
* The permission to access the download manager
*/
public static final String PERMISSION_ACCESS = "android.permission.ACCESS_DOWNLOAD_MANAGER";
/**
* The permission to access the download manager's advanced functions
*/
public static final String PERMISSION_ACCESS_ADVANCED =
"android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED";
/**
* The permission to access the all the downloads in the manager.
*/
public static final String PERMISSION_ACCESS_ALL =
"android.permission.ACCESS_ALL_DOWNLOADS";
/**
* The permission to directly access the download manager's cache
* directory
*/
public static final String PERMISSION_CACHE = "android.permission.ACCESS_CACHE_FILESYSTEM";
/**
* The permission to send broadcasts on download completion
*/
public static final String PERMISSION_SEND_INTENTS =
"android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS";
/**
* The permission to download files to the cache partition that won't be automatically
* purged when space is needed.
*/
public static final String PERMISSION_CACHE_NON_PURGEABLE =
"android.permission.DOWNLOAD_CACHE_NON_PURGEABLE";
/**
* The permission to download files without any system notification being shown.
*/
public static final String PERMISSION_NO_NOTIFICATION =
"android.permission.DOWNLOAD_WITHOUT_NOTIFICATION";
/**
* The content:// URI to access downloads owned by the caller's UID.
*/
public static final Uri CONTENT_URI =
Uri.parse("content://downloads/my_downloads");
public static final Uri ALL_DOWNLOADS_CONTENT_URI =
Uri.parse("content://downloads/all_downloads");
public static final String ACTION_DOWNLOAD_COMPLETED =
"android.intent.action.DOWNLOAD_COMPLETED";
public static final String ACTION_NOTIFICATION_CLICKED =
"android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
public static final String COLUMN_URI = "uri";
public static final String COLUMN_APP_DATA = "entity";
public static final String COLUMN_NO_INTEGRITY = "no_integrity";
public static final String COLUMN_FILE_NAME_HINT = "hint";
public static final String _DATA = "_data";
public static final String COLUMN_MIME_TYPE = "mimetype";
public static final String COLUMN_DESTINATION = "destination";
public static final String COLUMN_VISIBILITY = "visibility";
public static final String COLUMN_CONTROL = "control";
public static final String COLUMN_STATUS = "status";
public static final String COLUMN_LAST_MODIFICATION = "lastmod";
public static final String COLUMN_NOTIFICATION_PACKAGE = "notificationpackage";
public static final String COLUMN_NOTIFICATION_CLASS = "notificationclass";
public static final String COLUMN_NOTIFICATION_EXTRAS = "notificationextras";
public static final String COLUMN_COOKIE_DATA = "cookiedata";
public static final String COLUMN_USER_AGENT = "useragent";
public static final String COLUMN_REFERER = "referer";
public static final String COLUMN_TOTAL_BYTES = "total_bytes";
public static final String COLUMN_CURRENT_BYTES = "current_bytes";
public static final String COLUMN_OTHER_UID = "otheruid";
public static final String COLUMN_TITLE = "title";
public static final String COLUMN_DESCRIPTION = "description";
public static final String COLUMN_IS_PUBLIC_API = "is_public_api";
public static final String COLUMN_ALLOW_ROAMING = "allow_roaming";
public static final String COLUMN_ALLOWED_NETWORK_TYPES = "allowed_network_types";
public static final String COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI = "is_visible_in_downloads_ui";
public static final String COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT =
"bypass_recommended_size_limit";
public static final String COLUMN_DELETED = "deleted";
public static final String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
/*
* Lists the destinations that an application can specify for a download.
*/
public static final int DESTINATION_EXTERNAL = 0;
public static final int DESTINATION_CACHE_PARTITION = 1;
public static final int DESTINATION_CACHE_PARTITION_PURGEABLE = 2;
/**
* This download will be saved to the download manager's private
* partition, as with DESTINATION_CACHE_PARTITION, but the download
* will not proceed if the user is on a roaming data connection.
*/
public static final int DESTINATION_CACHE_PARTITION_NOROAMING = 3;
/**
* This download will be saved to the location given by the file URI in
* {@link #COLUMN_FILE_NAME_HINT}.
*/
public static final int DESTINATION_FILE_URI = 4;
/**
* This download is allowed to run.
*/
public static final int CONTROL_RUN = 0;
/**
* This download must pause at the first opportunity.
*/
public static final int CONTROL_PAUSED = 1;
/**
* Returns whether the status is informational (i.e. 1xx).
*/
public static boolean isStatusInformational(int status) {
return (status >= 100 && status < 200);
}
/**
* Returns whether the status is a success (i.e. 2xx).
*/
public static boolean isStatusSuccess(int status) {
return (status >= 200 && status < 300);
}
/**
* Returns whether the status is an error (i.e. 4xx or 5xx).
*/
public static boolean isStatusError(int status) {
return (status >= 400 && status < 600);
}
/**
* Returns whether the status is a client error (i.e. 4xx).
*/
public static boolean isStatusClientError(int status) {
return (status >= 400 && status < 500);
}
/**
* Returns whether the status is a server error (i.e. 5xx).
*/
public static boolean isStatusServerError(int status) {
return (status >= 500 && status < 600);
}
/**
* Returns whether the download has completed (either with success or
* error).
*/
public static boolean isStatusCompleted(int status) {
return (status >= 200 && status < 300) || (status >= 400 && status < 600);
}
/**
* This download hasn't stated yet
*/
public static final int STATUS_PENDING = 190;
/**
* This download has started
*/
public static final int STATUS_RUNNING = 192;
/**
* This download has been paused by the owning app.
*/
public static final int STATUS_PAUSED_BY_APP = 193;
/**
* This download encountered some network error and is waiting before retrying the request.
*/
public static final int STATUS_WAITING_TO_RETRY = 194;
/**
* This download is waiting for network connectivity to proceed.
*/
public static final int STATUS_WAITING_FOR_NETWORK = 195;
/**
* This download exceeded a size limit for mobile networks and is waiting for a Wi-Fi
* connection to proceed.
*/
public static final int STATUS_QUEUED_FOR_WIFI = 196;
public static final int STATUS_SUCCESS = 200;
public static final int STATUS_BAD_REQUEST = 400;
/**
* This download can't be performed because the content type cannot be
* handled.
*/
public static final int STATUS_NOT_ACCEPTABLE = 406;
public static final int STATUS_LENGTH_REQUIRED = 411;
/**
* This download was interrupted and cannot be resumed.
* This is the code for the HTTP error "Precondition Failed", and it is
* also used in situations where the client doesn't have an ETag at all.
*/
public static final int STATUS_PRECONDITION_FAILED = 412;
/**
* The lowest-valued error status that is not an actual HTTP status code.
*/
public static final int MIN_ARTIFICIAL_ERROR_STATUS = 488;
/**
* The requested destination file already exists.
*/
public static final int STATUS_FILE_ALREADY_EXISTS_ERROR = 488;
/**
* Some possibly transient error occurred, but we can't resume the download.
*/
public static final int STATUS_CANNOT_RESUME = 489;
/**
* This download was canceled
*/
public static final int STATUS_CANCELED = 490;
public static final int STATUS_UNKNOWN_ERROR = 491;
public static final int STATUS_FILE_ERROR = 492;
/**
* This download couldn't be completed because of an HTTP
* redirect response that the download manager couldn't
* handle.
*/
public static final int STATUS_UNHANDLED_REDIRECT = 493;
/**
* This download couldn't be completed because of an
* unspecified unhandled HTTP code.
*/
public static final int STATUS_UNHANDLED_HTTP_CODE = 494;
/**
* This download couldn't be completed because of an
* error receiving or processing data at the HTTP level.
*/
public static final int STATUS_HTTP_DATA_ERROR = 495;
/**
* This download couldn't be completed because of an
* HttpException while setting up the request.
*/
public static final int STATUS_HTTP_EXCEPTION = 496;
/**
* This download couldn't be completed because there were
* too many redirects.
*/
public static final int STATUS_TOO_MANY_REDIRECTS = 497;
/**
* This download couldn't be completed due to insufficient storage
* space. Typically, this is because the SD card is full.
*/
public static final int STATUS_INSUFFICIENT_SPACE_ERROR = 498;
/**
* This download couldn't be completed because no external storage
* device was found. Typically, this is because the SD card is not
* mounted.
*/
public static final int STATUS_DEVICE_NOT_FOUND_ERROR = 499;
/**
* This download is visible but only shows in the notifications
* while it's in progress.
*/
public static final int VISIBILITY_VISIBLE = 0;
/**
* This download is visible and shows in the notifications while
* in progress and after completion.
*/
public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1;
/**
* This download doesn't show in the UI or in the notifications.
*/
public static final int VISIBILITY_HIDDEN = 2;
/**
* Constants related to HTTP request headers associated with each download.
*/
public static class RequestHeaders {
public static final String HEADERS_DB_TABLE = "request_headers";
public static final String COLUMN_DOWNLOAD_ID = "download_id";
public static final String COLUMN_HEADER = "header";
public static final String COLUMN_VALUE = "value";
/**
* Path segment to add to a download URI to retrieve request headers
*/
public static final String URI_SEGMENT = "headers";
/**
* Prefix for ContentValues keys that contain HTTP header lines, to be passed to
* DownloadProvider.insert().
*/
public static final String INSERT_KEY_PREFIX = "http_header_";
}
}
}
公共类DownloadManager{private static最终字符串TAG="DownloadManager";
public final static String COLUMN_ID = BaseColumns._ID;
public final static String COLUMN_TITLE = "title";
public final static String COLUMN_DESCRIPTION = "description";
public final static String COLUMN_URI = "uri";
public final static String COLUMN_MEDIA_TYPE = "media_type";
public final static String COLUMN_TOTAL_SIZE_BYTES = "total_size";
public final static String COLUMN_LOCAL_URI = "local_uri";
public final static String COLUMN_STATUS = "status";
public final static String COLUMN_REASON = "reason";
public final static String COLUMN_BYTES_DOWNLOADED_SO_FAR = "bytes_so_far";
public final static String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
public static final String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
public final static int STATUS_PENDING = 1 << 0;
public final static int STATUS_RUNNING = 1 << 1;
public final static int STATUS_PAUSED = 1 << 2;
public final static int STATUS_SUCCESSFUL = 1 << 3;
public final static int STATUS_FAILED = 1 << 4;
public final static int ERROR_UNKNOWN = 1000;
public final static int ERROR_FILE_ERROR = 1001;
public final static int ERROR_UNHANDLED_HTTP_CODE = 1002;
public final static int ERROR_HTTP_DATA_ERROR = 1004;
public final static int ERROR_TOO_MANY_REDIRECTS = 1005;
public final static int ERROR_INSUFFICIENT_SPACE = 1006;
public final static int ERROR_DEVICE_NOT_FOUND = 1007;
public final static int ERROR_CANNOT_RESUME = 1008;
public final static int ERROR_FILE_ALREADY_EXISTS = 1009;
public final static int PAUSED_WAITING_TO_RETRY = 1;
public final static int PAUSED_WAITING_FOR_NETWORK = 2;
public final static int PAUSED_QUEUED_FOR_WIFI = 3;
public final static int PAUSED_UNKNOWN = 4;
public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
public final static String ACTION_NOTIFICATION_CLICKED = "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
public final static String ACTION_VIEW_DOWNLOADS = "android.intent.action.VIEW_DOWNLOADS";
public static final String EXTRA_DOWNLOAD_ID = "extra_download_id";
// this array must contain all public columns
private static final String[] COLUMNS = new String[] { COLUMN_ID,
COLUMN_MEDIAPROVIDER_URI, COLUMN_TITLE, COLUMN_DESCRIPTION,
COLUMN_URI, COLUMN_MEDIA_TYPE, COLUMN_TOTAL_SIZE_BYTES,
COLUMN_LOCAL_URI, COLUMN_STATUS, COLUMN_REASON,
COLUMN_BYTES_DOWNLOADED_SO_FAR, COLUMN_LAST_MODIFIED_TIMESTAMP };
// columns to request from DownloadProvider
private static final String[] UNDERLYING_COLUMNS = new String[] {
Downloads.Impl._ID, Downloads.Impl.COLUMN_MEDIAPROVIDER_URI,
Downloads.COLUMN_TITLE, Downloads.COLUMN_DESCRIPTION,
Downloads.COLUMN_URI, Downloads.COLUMN_MIME_TYPE,
Downloads.COLUMN_TOTAL_BYTES, Downloads.COLUMN_STATUS,
Downloads.COLUMN_CURRENT_BYTES, Downloads.COLUMN_LAST_MODIFICATION,
Downloads.COLUMN_DESTINATION, Downloads.Impl.COLUMN_FILE_NAME_HINT,
Downloads.Impl._DATA, };
private static final Set<String> LONG_COLUMNS = new HashSet<String>(
Arrays.asList(COLUMN_ID, COLUMN_TOTAL_SIZE_BYTES, COLUMN_STATUS,
COLUMN_REASON, COLUMN_BYTES_DOWNLOADED_SO_FAR,
COLUMN_LAST_MODIFIED_TIMESTAMP));
public static class Request {
public static final int NETWORK_MOBILE = 1 << 0;
public static final int NETWORK_WIFI = 1 << 1;
private Uri mUri;
private Uri mDestinationUri;
private List<Pair<String, String>> mRequestHeaders = new ArrayList<Pair<String, String>>();
private CharSequence mTitle;
private CharSequence mDescription;
private boolean mShowNotification = true;
private String mMimeType;
private boolean mRoamingAllowed = true;
private int mAllowedNetworkTypes = ~0; // default to all network types
// allowed
private boolean mIsVisibleInDownloadsUi = true;
/**
* @param uri
* the HTTP URI to download.
*/
public Request(Uri uri) {
if (uri == null) {
throw new NullPointerException();
}
String scheme = uri.getScheme();
if (scheme == null
|| !(scheme.equals("http") || scheme.equals("https"))) {
throw new IllegalArgumentException(
"Can only download HTTP URIs: " + uri);
}
mUri = uri;
}
public Request setDestinationUri(Uri uri) {
mDestinationUri = uri;
return this;
}
public Request setDestinationInExternalFilesDir(Context context,
String dirType, String subPath) {
setDestinationFromBase(context.getExternalFilesDir(dirType),
subPath);
return this;
}
public Request setDestinationInExternalPublicDir(String dirType,
String subPath) {
setDestinationFromBase(
Environment.getExternalStoragePublicDirectory(dirType),
subPath);
return this;
}
private void setDestinationFromBase(File base, String subPath) {
if (subPath == null) {
throw new NullPointerException("subPath cannot be null");
}
mDestinationUri = Uri.withAppendedPath(Uri.fromFile(base), subPath);
}
public Request addRequestHeader(String header, String value) {
if (header == null) {
throw new NullPointerException("header cannot be null");
}
if (header.contains(":")) {
throw new IllegalArgumentException("header may not contain ':'");
}
if (value == null) {
value = "";
}
mRequestHeaders.add(Pair.create(header, value));
return this;
}
public Request setTitle(CharSequence title) {
mTitle = title;
return this;
}
public Request setDescription(CharSequence description) {
mDescription = description;
return this;
}
public Request setMimeType(String mimeType) {
mMimeType = mimeType;
return this;
}
public Request setShowRunningNotification(boolean show) {
mShowNotification = show;
return this;
}
public Request setAllowedNetworkTypes(int flags) {
mAllowedNetworkTypes = flags;
return this;
}
public Request setAllowedOverRoaming(boolean allowed) {
mRoamingAllowed = allowed;
return this;
}
public Request setVisibleInDownloadsUi(boolean isVisible) {
mIsVisibleInDownloadsUi = isVisible;
return this;
}
/**
* @return ContentValues to be passed to DownloadProvider.insert()
*/
ContentValues toContentValues(String packageName) {
ContentValues values = new ContentValues();
assert mUri != null;
values.put(Downloads.COLUMN_URI, mUri.toString());
values.put(Downloads.Impl.COLUMN_IS_PUBLIC_API, true);
values.put(Downloads.COLUMN_NOTIFICATION_PACKAGE, packageName);
if (mDestinationUri != null) {
values.put(Downloads.COLUMN_DESTINATION,
Downloads.Impl.DESTINATION_FILE_URI);
values.put(Downloads.COLUMN_FILE_NAME_HINT,
mDestinationUri.toString());
} else {
values.put(Downloads.COLUMN_DESTINATION,
Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE);
}
if (!mRequestHeaders.isEmpty()) {
encodeHttpHeaders(values);
}
putIfNonNull(values, Downloads.COLUMN_TITLE, mTitle);
putIfNonNull(values, Downloads.COLUMN_DESCRIPTION, mDescription);
putIfNonNull(values, Downloads.COLUMN_MIME_TYPE, mMimeType);
values.put(Downloads.COLUMN_VISIBILITY,
mShowNotification ? Downloads.VISIBILITY_VISIBLE
: Downloads.VISIBILITY_HIDDEN);
values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES,
mAllowedNetworkTypes);
values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, mRoamingAllowed);
values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI,
mIsVisibleInDownloadsUi);
return values;
}
private void encodeHttpHeaders(ContentValues values) {
int index = 0;
for (Pair<String, String> header : mRequestHeaders) {
String headerString = header.first + ": " + header.second;
values.put(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX
+ index, headerString);
index++;
}
}
private void putIfNonNull(ContentValues contentValues, String key,
Object value) {
if (value != null) {
contentValues.put(key, value.toString());
}
}
}
/**
* This class may be used to filter download manager queries.
*/
public static class Query {
/**
* Constant for use with {@link #orderBy}
*
* @hide
*/
public static final int ORDER_ASCENDING = 1;
/**
* Constant for use with {@link #orderBy}
*
* @hide
*/
public static final int ORDER_DESCENDING = 2;
private long[] mIds = null;
private Integer mStatusFlags = null;
private String mOrderByColumn = Downloads.COLUMN_LAST_MODIFICATION;
private int mOrderDirection = ORDER_DESCENDING;
private boolean mOnlyIncludeVisibleInDownloadsUi = false;
/**
* Include only the downloads with the given IDs.
*
* @return this object
*/
public Query setFilterById(long... ids) {
mIds = ids;
return this;
}
/**
* Include only downloads with status matching any the given status
* flags.
*
* @param flags
* any combination of the STATUS_* bit flags
* @return this object
*/
public Query setFilterByStatus(int flags) {
mStatusFlags = flags;
return this;
}
/**
* Controls whether this query includes downloads not visible in the
* system's Downloads UI.
*
* @param value
* if true, this query will only include downloads that
* should be displayed in the system's Downloads UI; if false
* (the default), this query will include both visible and
* invisible downloads.
* @return this object
* @hide
*/
public Query setOnlyIncludeVisibleInDownloadsUi(boolean value) {
mOnlyIncludeVisibleInDownloadsUi = value;
return this;
}
/**
* Change the sort order of the returned Cursor.
*
* @param column
* one of the COLUMN_* constants; currently, only
* {@link #COLUMN_LAST_MODIFIED_TIMESTAMP} and
* {@link #COLUMN_TOTAL_SIZE_BYTES} are supported.
* @param direction
* either {@link #ORDER_ASCENDING} or
* {@link #ORDER_DESCENDING}
* @return this object
* @hide
*/
public Query orderBy(String column, int direction) {
if (direction != ORDER_ASCENDING && direction != ORDER_DESCENDING) {
throw new IllegalArgumentException("Invalid direction: "
+ direction);
}
if (column.equals(COLUMN_LAST_MODIFIED_TIMESTAMP)) {
mOrderByColumn = Downloads.COLUMN_LAST_MODIFICATION;
} else if (column.equals(COLUMN_TOTAL_SIZE_BYTES)) {
mOrderByColumn = Downloads.COLUMN_TOTAL_BYTES;
} else {
throw new IllegalArgumentException("Cannot order by " + column);
}
mOrderDirection = direction;
return this;
}
/**
* Run this query using the given ContentResolver.
*
* @param projection
* the projection to pass to ContentResolver.query()
* @return the Cursor returned by ContentResolver.query()
*/
Cursor runQuery(ContentResolver resolver, String[] projection,
Uri baseUri) {
Uri uri = baseUri;
List<String> selectionParts = new ArrayList<String>();
String[] selectionArgs = null;
if (mIds != null) {
selectionParts.add(getWhereClauseForIds(mIds));
selectionArgs = getWhereArgsForIds(mIds);
}
if (mStatusFlags != null) {
List<String> parts = new ArrayList<String>();
if ((mStatusFlags & STATUS_PENDING) != 0) {
parts.add(statusClause("=", Downloads.STATUS_PENDING));
}
if ((mStatusFlags & STATUS_RUNNING) != 0) {
parts.add(statusClause("=", Downloads.STATUS_RUNNING));
}
if ((mStatusFlags & STATUS_PAUSED) != 0) {
parts.add(statusClause("=",
Downloads.Impl.STATUS_PAUSED_BY_APP));
parts.add(statusClause("=",
Downloads.Impl.STATUS_WAITING_TO_RETRY));
parts.add(statusClause("=",
Downloads.Impl.STATUS_WAITING_FOR_NETWORK));
parts.add(statusClause("=",
Downloads.Impl.STATUS_QUEUED_FOR_WIFI));
}
if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
parts.add(statusClause("=", Downloads.STATUS_SUCCESS));
}
if ((mStatusFlags & STATUS_FAILED) != 0) {
parts.add("(" + statusClause(">=", 400) + " AND "
+ statusClause("<", 600) + ")");
}
selectionParts.add(joinStrings(" OR ", parts));
}
if (mOnlyIncludeVisibleInDownloadsUi) {
selectionParts
.add(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI
+ " != '0'");
}
// only return rows which are not marked 'deleted = 1'
selectionParts.add(Downloads.Impl.COLUMN_DELETED + " != '1'");
String selection = joinStrings(" AND ", selectionParts);
String orderDirection = (mOrderDirection == ORDER_ASCENDING ? "ASC"
: "DESC");
String orderBy = mOrderByColumn + " " + orderDirection;
return resolver.query(uri, projection, selection, selectionArgs,
orderBy);
}
private String joinStrings(String joiner, Iterable<String> parts) {
StringBuilder builder = new StringBuilder();
boolean first = true;
for (String part : parts) {
if (!first) {
builder.append(joiner);
}
builder.append(part);
first = false;
}
return builder.toString();
}
private String statusClause(String operator, int value) {
return Downloads.COLUMN_STATUS + operator + "'" + value + "'";
}
}
private ContentResolver mResolver;
private String mPackageName;
private Uri mBaseUri = Downloads.Impl.CONTENT_URI;
/**
* @hide
*/
public DownloadManager(ContentResolver resolver, String packageName) {
mResolver = resolver;
mPackageName = packageName;
}
/**
* Makes this object access the download provider through /all_downloads
* URIs rather than /my_downloads URIs, for clients that have permission to
* do so.
*
* @hide
*/
public void setAccessAllDownloads(boolean accessAllDownloads) {
if (accessAllDownloads) {
mBaseUri = Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI;
} else {
mBaseUri = Downloads.Impl.CONTENT_URI;
}
}
public long enqueue(Request request) {
ContentValues values = request.toContentValues(mPackageName);
Uri downloadUri = mResolver.insert(Downloads.CONTENT_URI, values);
long id = Long.parseLong(downloadUri.getLastPathSegment());
return id;
}
public int markRowDeleted(long... ids) {
if (ids == null || ids.length == 0) {
// called with nothing to remove!
throw new IllegalArgumentException(
"input param 'ids' can't be null");
}
ContentValues values = new ContentValues();
values.put(Downloads.Impl.COLUMN_DELETED, 1);
return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
getWhereArgsForIds(ids));
}
public int remove(long... ids) {
if (ids == null || ids.length == 0) {
// called with nothing to remove!
throw new IllegalArgumentException(
"input param 'ids' can't be null");
}
return mResolver.delete(mBaseUri, getWhereClauseForIds(ids),
getWhereArgsForIds(ids));
}
public Cursor query(Query query) {
Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS,
mBaseUri);
if (underlyingCursor == null) {
return null;
}
return new CursorTranslator(underlyingCursor, mBaseUri);
}
public ParcelFileDescriptor openDownloadedFile(long id)
throws FileNotFoundException {
return mResolver.openFileDescriptor(getDownloadUri(id), "r");
}
public void restartDownload(long... ids) {
Cursor cursor = query(new Query().setFilterById(ids));
try {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor
.moveToNext()) {
int status = cursor
.getInt(cursor.getColumnIndex(COLUMN_STATUS));
if (status != STATUS_SUCCESSFUL && status != STATUS_FAILED) {
throw new IllegalArgumentException(
"Cannot restart incomplete download: "
+ cursor.getLong(cursor
.getColumnIndex(COLUMN_ID)));
}
}
} finally {
cursor.close();
}
ContentValues values = new ContentValues();
values.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0);
values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1);
values.putNull(Downloads.Impl._DATA);
values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING);
mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
getWhereArgsForIds(ids));
}
/**
* Get the DownloadProvider URI for the download with the given ID.
*/
Uri getDownloadUri(long id) {
return ContentUris.withAppendedId(mBaseUri, id);
}
/**
* Get a parameterized SQL WHERE clause to select a bunch of IDs.
*/
static String getWhereClauseForIds(long[] ids) {
StringBuilder whereClause = new StringBuilder();
whereClause.append("(");
for (int i = 0; i < ids.length; i++) {
if (i > 0) {
whereClause.append("OR ");
}
whereClause.append(Downloads.Impl._ID);
whereClause.append(" = ? ");
}
whereClause.append(")");
return whereClause.toString();
}
/**
* Get the selection args for a clause returned by
* {@link #getWhereClauseForIds(long[])}.
*/
static String[] getWhereArgsForIds(long[] ids) {
String[] whereArgs = new String[ids.length];
for (int i = 0; i < ids.length; i++) {
whereArgs[i] = Long.toString(ids[i]);
}
return whereArgs;
}
/**
* This class wraps a cursor returned by DownloadProvider -- the
* "underlying cursor" -- and presents a different set of columns, those
* defined in the DownloadManager.COLUMN_* constants. Some columns
* correspond directly to underlying values while others are computed from
* underlying data.
*/
private static class CursorTranslator extends CursorWrapper {
private Uri mBaseUri;
public CursorTranslator(Cursor cursor, Uri baseUri) {
super(cursor);
mBaseUri = baseUri;
}
@Override
public int getColumnIndex(String columnName) {
return Arrays.asList(COLUMNS).indexOf(columnName);
}
@Override
public int getColumnIndexOrThrow(String columnName)
throws IllegalArgumentException {
int index = getColumnIndex(columnName);
if (index == -1) {
throw new IllegalArgumentException("No such column: "
+ columnName);
}
return index;
}
@Override
public String getColumnName(int columnIndex) {
int numColumns = COLUMNS.length;
if (columnIndex < 0 || columnIndex >= numColumns) {
throw new IllegalArgumentException("Invalid column index "
+ columnIndex + ", " + numColumns + " columns exist");
}
return COLUMNS[columnIndex];
}
@Override
public String[] getColumnNames() {
String[] returnColumns = new String[COLUMNS.length];
System.arraycopy(COLUMNS, 0, returnColumns, 0, COLUMNS.length);
return returnColumns;
}
@Override
public int getColumnCount() {
return COLUMNS.length;
}
@Override
public byte[] getBlob(int columnIndex) {
throw new UnsupportedOperationException();
}
@Override
public double getDouble(int columnIndex) {
return getLong(columnIndex);
}
private boolean isLongColumn(String column) {
return LONG_COLUMNS.contains(column);
}
@Override
public float getFloat(int columnIndex) {
return (float) getDouble(columnIndex);
}
@Override
public int getInt(int columnIndex) {
return (int) getLong(columnIndex);
}
@Override
public long getLong(int columnIndex) {
return translateLong(getColumnName(columnIndex));
}
@Override
public short getShort(int columnIndex) {
return (short) getLong(columnIndex);
}
@Override
public String getString(int columnIndex) {
return translateString(getColumnName(columnIndex));
}
private String translateString(String column) {
if (isLongColumn(column)) {
return Long.toString(translateLong(column));
}
if (column.equals(COLUMN_TITLE)) {
return getUnderlyingString(Downloads.COLUMN_TITLE);
}
if (column.equals(COLUMN_DESCRIPTION)) {
return getUnderlyingString(Downloads.COLUMN_DESCRIPTION);
}
if (column.equals(COLUMN_URI)) {
return getUnderlyingString(Downloads.COLUMN_URI);
}
if (column.equals(COLUMN_MEDIA_TYPE)) {
return getUnderlyingString(Downloads.COLUMN_MIME_TYPE);
}
if (column.equals(COLUMN_MEDIAPROVIDER_URI)) {
return getUnderlyingString(Downloads.Impl.COLUMN_MEDIAPROVIDER_URI);
}
assert column.equals(COLUMN_LOCAL_URI);
return getLocalUri();
}
private String getLocalUri() {
long destinationType = getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION);
if (destinationType == Downloads.Impl.DESTINATION_FILE_URI) {
// return client-provided file URI for external download
return getUnderlyingString(Downloads.Impl.COLUMN_FILE_NAME_HINT);
}
if (destinationType == Downloads.Impl.DESTINATION_EXTERNAL) {
// return stored destination for legacy external download
String localPath = getUnderlyingString(Downloads.Impl._DATA);
if (localPath == null) {
return null;
}
return Uri.fromFile(new File(localPath)).toString();
}
// return content URI for cache download
long downloadId = getUnderlyingLong(Downloads.Impl._ID);
return ContentUris.withAppendedId(mBaseUri, downloadId).toString();
}
private long translateLong(String column) {
if (!isLongColumn(column)) {
// mimic behavior of underlying cursor -- most likely, throw
// NumberFormatException
return Long.valueOf(translateString(column));
}
if (column.equals(COLUMN_ID)) {
return getUnderlyingLong(Downloads.Impl._ID);
}
if (column.equals(COLUMN_TOTAL_SIZE_BYTES)) {
return getUnderlyingLong(Downloads.COLUMN_TOTAL_BYTES);
}
if (column.equals(COLUMN_STATUS)) {
return translateStatus((int) getUnderlyingLong(Downloads.COLUMN_STATUS));
}
if (column.equals(COLUMN_REASON)) {
return getReason((int) getUnderlyingLong(Downloads.COLUMN_STATUS));
}
if (column.equals(COLUMN_BYTES_DOWNLOADED_SO_FAR)) {
return getUnderlyingLong(Downloads.COLUMN_CURRENT_BYTES);
}
assert column.equals(COLUMN_LAST_MODIFIED_TIMESTAMP);
return getUnderlyingLong(Downloads.COLUMN_LAST_MODIFICATION);
}
private long getReason(int status) {
switch (translateStatus(status)) {
case STATUS_FAILED:
return getErrorCode(status);
case STATUS_PAUSED:
return getPausedReason(status);
default:
return 0; // arbitrary value when status is not an error
}
}
private long getPausedReason(int status) {
switch (status) {
case Downloads.Impl.STATUS_WAITING_TO_RETRY:
return PAUSED_WAITING_TO_RETRY;
case Downloads.Impl.STATUS_WAITING_FOR_NETWORK:
return PAUSED_WAITING_FOR_NETWORK;
case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
return PAUSED_QUEUED_FOR_WIFI;
default:
return PAUSED_UNKNOWN;
}
}
private long getErrorCode(int status) {
if ((400 <= status && status < Downloads.Impl.MIN_ARTIFICIAL_ERROR_STATUS)
|| (500 <= status && status < 600)) {
// HTTP status code
return status;
}
switch (status) {
case Downloads.STATUS_FILE_ERROR:
return ERROR_FILE_ERROR;
case Downloads.STATUS_UNHANDLED_HTTP_CODE:
case Downloads.STATUS_UNHANDLED_REDIRECT:
return ERROR_UNHANDLED_HTTP_CODE;
case Downloads.STATUS_HTTP_DATA_ERROR:
return ERROR_HTTP_DATA_ERROR;
case Downloads.STATUS_TOO_MANY_REDIRECTS:
return ERROR_TOO_MANY_REDIRECTS;
case Downloads.STATUS_INSUFFICIENT_SPACE_ERROR:
return ERROR_INSUFFICIENT_SPACE;
case Downloads.STATUS_DEVICE_NOT_FOUND_ERROR:
return ERROR_DEVICE_NOT_FOUND;
case Downloads.Impl.STATUS_CANNOT_RESUME:
return ERROR_CANNOT_RESUME;
case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR:
return ERROR_FILE_ALREADY_EXISTS;
default:
return ERROR_UNKNOWN;
}
}
private long getUnderlyingLong(String column) {
return super.getLong(super.getColumnIndex(column));
}
private String getUnderlyingString(String column) {
return super.getString(super.getColumnIndex(column));
}
private int translateStatus(int status) {
switch (status) {
case Downloads.STATUS_PENDING:
return STATUS_PENDING;
case Downloads.STATUS_RUNNING:
return STATUS_RUNNING;
case Downloads.Impl.STATUS_PAUSED_BY_APP:
case Downloads.Impl.STATUS_WAITING_TO_RETRY:
case Downloads.Impl.STATUS_WAITING_FOR_NETWORK:
case Downloads.Impl.STATUS_QUEUED_FOR_WIFI:
return STATUS_PAUSED;
case Downloads.STATUS_SUCCESS:
return STATUS_SUCCESSFUL;
default:
assert Downloads.isStatusError(status);
return STATUS_FAILED;
}
}
}
}