/*
* Copyright (C) 2010 mAPPn.Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.lan.nicehair.common.download;
import java.util.ArrayList;
import java.util.List;
import com.lan.nicehair.activity.MainActivity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.provider.BaseColumns;
import android.text.TextUtils;
/**
* The download manager is a system service that handles long-running HTTP downloads. Clients may
* request that a URI be downloaded to a particular destination file. The download manager will
* conduct the download in the background, taking care of HTTP interactions and retrying downloads
* after failures or across connectivity changes and system reboots.
*
* @author andrew
* @date 2011-4-27
* @since Version 0.7.0
*/
public class DownloadManager {
/**
* Value of {@link #COLUMN_STATUS} when the download is waiting to start.
*/
public final static int STATUS_PENDING = 1 << 0;
/**
* Value of {@link #COLUMN_STATUS} when the download is currently running.
*/
public final static int STATUS_RUNNING = 1 << 1;
/**
* Value of {@link #COLUMN_STATUS} when the download is waiting to retry or resume.
*/
public final static int STATUS_PAUSED = 1 << 2;
/**
* Value of {@link #COLUMN_STATUS} when the download has successfully completed.
*/
public final static int STATUS_SUCCESSFUL = 1 << 3;
/**
* Value of {@link #COLUMN_STATUS} when the download has failed (and will not be retried).
*/
public final static int STATUS_FAILED = 1 << 4;
private ContentResolver mResolver;
private String mPackageName;
private Uri mBaseUri = Impl.CONTENT_URI;
/**
* 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(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;
}
public DownloadManager(ContentResolver resolver, String packageName) {
mResolver = resolver;
mPackageName = packageName;
}
/**
* Enqueue a new download. The download will start automatically once the download manager is
* ready to execute it and connectivity is available.
*
* @param request the parameters specifying this download
* @return an ID for the download, unique across the system. This ID is used to make future
* calls related to this download.
*/
public long enqueue(Request request) {
ContentValues values = request.toContentValues(mPackageName);
// use the title as the file's name
values.put(Impl.COLUMN_FILE_NAME_HINT, (String) request.mTitle);
values.put(Impl.COLUMN_PACKAGE_NAME, request.mPackageName);
values.put(Impl.COLUMN_NOTIFICATION_CLASS, MainActivity.class.getName());
values.put(Impl.COLUMN_MD5, request.mMD5);
if (request.mSourceType == Constants.DOWNLOAD_FROM_OTA) {
values.put(Impl.COLUMN_DESTINATION, DownloadManager.Impl.DESTINATION_CACHE_PARTITION);
} else {
values.put(Impl.COLUMN_DESTINATION, request.mDestination);
}
Uri downloadUri = mResolver.insert(Impl.CONTENT_URI, values);
if (downloadUri == null) {
return -1;
}
long id = Long.parseLong(downloadUri.getLastPathSegment());
return id;
}
public long enqueueWaitRequest(Request request) {
ContentValues values = request.toContentValues(mPackageName);
// use the title as the file's name
values.put(Impl.COLUMN_FILE_NAME_HINT, (String) request.mTitle);
values.put(Impl.COLUMN_PACKAGE_NAME, request.mPackageName);
// TODO values.put(Impl.COLUMN_NOTIFICATION_CLASS, LocalManagerActivity.class.getName());
values.put(Impl.COLUMN_MD5, request.mMD5);
values.put(Impl.COLUMN_DESTINATION, request.mDestination);
values.put(Impl.COLUMN_CONTROL, Impl.CONTROL_PENDING);
Uri downloadUri = mResolver.insert(Impl.CONTENT_URI, values);
if (downloadUri == null) {
return -1;
}
long id = Long.parseLong(downloadUri.getLastPathSegment());
return id;
}
/**
* 隐藏已经下载完成的OTA任务
*/
public int hideDownload(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(Impl.COLUMN_VISIBILITY, Impl.VISIBILITY_HIDDEN);
return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
getWhereArgsForIds(ids));
}
/**
* Marks the specified download as 'paused'.
*
* @param ids the IDs of the downloads to be marked 'paused'
* @return the number of downloads actually updated
*/
public int pauseDownload(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(Impl.COLUMN_CONTROL, Impl.CONTROL_PAUSED);
return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
getWhereArgsForIds(ids));
}
/**
* Marks the specified download as 'resumed'.
*
* @param ids the IDs of the downloads to be marked 'paused'
* @return the number of downloads actually updated
*/
public int resumeDownload(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(Impl.COLUMN_CONTROL, Impl.CONTROL_RUN);
return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
getWhereArgsForIds(ids));
}
public int cancelDownload(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(Impl.COLUMN_STATUS, Impl.STATUS_CANCELED);
return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
getWhereArgsForIds(ids));
}
/**
* 更新软件的状态为已经安装
* @param packageName 包名
*/
public void completeInstallation(final String packageName) {
if (TextUtils.isEmpty(packageName)) {
return;
}
ContentValues values = new ContentValues();
values.put(Impl.COLUMN_STATUS, Impl.STATUS_INSTALLED);
values.put(Impl.COLUMN_VISIBILITY, Impl.VISIBILITY_HIDDEN);
values.put(Impl.COLUMN_DELETED, 1);
mResolver.update(mBaseUri, values,
getWhereClauseForPackageName(),
getWhereArgsForPackageName(packageName));
}
static String getWhereClauseForPackageName() {
StringBuilder whereClause = new StringBuilder();
whereClause.append("(");
whereClause.append(Impl.COLUMN_STATUS);
whereClause.append(" = ? AND ");
whereClause.append(Impl.COLUMN_PACKAGE_NAME);
whereClause.append(" = ? )");
return whereClause.toString();
}
static String[] getWhereArgsForPackageName(String packageName) {
return new String[] { String.valueOf(Impl.STATUS_SUCCESS), packageName };
}
/**
* 获取下载中的任务(包括下载完成、下载取消)<br>
*/
public Cursor getDownloadingApks() {
return mResolver.query(mBaseUri, new String[]{
Impl._ID,
Impl.COLUMN_DATA,
Impl.COLUMN_TITLE,
Impl.COLUMN_DESCRIPTION,
Impl.COLUMN_CURRENT_BYTES,
Impl.COLUMN_TOTAL_BYTES,
Impl.COLUMN_STATUS,
Impl.COLUMN_PACKAGE_NAME,
Impl.COLUMN_NOTIFICATION_EXTRAS
}, "(((" + Impl.COLUMN_STATUS + " >= '190' AND "
+ Impl.COLUMN_STATUS + " <= '200') OR "
+ Impl.COLUMN_STATUS + " = '" + Impl.STATUS_CANCELED + "') AND "
+ Impl.COLUMN_DESTINATION + " = '" + Impl.DESTINATION_EXTERNAL + "' AND "
+ Impl.COLUMN_MIME_TYPE + " = '" + Constants.MIMETYPE_APK + "')", null, null);
}
public Cursor getDownloadErrorApks() {
return mResolver.query(mBaseUri, new String[]{
Impl._ID,
Impl.COLUMN_TITLE,
Impl.COLUMN_STATUS
}, "((" + Impl.COLUMN_STATUS + " >= '400' AND "
+ Impl.COLUMN_STATUS + " < '500') AND "
+ Impl.COLUMN_DESTINATION + " = '" + Impl.DESTINATION_EXTERNAL + "' AND "
+ Impl.COLUMN_MIME_TYPE + " = '" + Constants.MIMETYPE_APK + "')", null, null);
}
/**
* Marks the specified download as 'to be deleted'. This is done when a completed download
* is to be removed but the row was stored without enough info to delete the corresponding
* metadata from Mediaprovider database. Actual cleanup of this row is done in DownloadService.
*
* @param ids the IDs of the downloads to be marked 'deleted'
* @return the number of downloads actually updated
*/
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(Impl.COLUMN_DELETED, 1);
return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
getWhereArgsForIds(ids));
}
/**
* Cancel downloads and remove them from the download manager. Each download will be stopped if
* it was running, and it will no longer be accessible through the download manager. If a file
* was already downloaded to external storage, it will not be deleted.
*
* @param ids the IDs of the downloads to remove
* @return the number of downloads actually removed
*/
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));
}
/**
* Query the download manager about downloads that have been requested.
* @param query parameters specifying filters for this query
* @return a Cursor over the result set of downloads, with columns consisting of all the
* COLUMN_* constants.
*/
public Cursor query(Query query) {
return query.runQuery(mResolver, null, mBaseUri);
}
/**
* Restart the given downloads, which must have already completed (successfully or not). This
* method will only work when called from within the download manager's process.
* @param ids the IDs of the downloads
*/
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(Impl.COLUMN_STATUS));
if (status != STATUS_SUCCESSFUL && status != STATUS_FAILED) {
throw new IllegalArgumentException("Cannot restart incomplete download: "
+ cursor.getLong(cursor.getColumnIndex(Impl.COLUMN_ID)));
}
}
} finally {
cursor.close();
}
ContentValues values = new ContentValues();
values.put(Impl.COLUMN_CURRENT_BYTES, 0);
values.put(Impl.COLUMN_TOTAL_BYTES, -1);
values.putNull(Impl.COLUMN_DATA);
values.put(Impl.COLUMN_STATUS, Impl.STATUS_PENDING);
mResolver.update(mBaseUri, values, getWhereClauseForIds(ids), getWhereArgsForIds(ids));
}
/**
* This class contains all the information necessary to request a new download. The URI is the
* only required parameter.
*
* Note that the default download destination is a shared volume where the system might delete
* your file if it needs to reclaim space for system use. If this is a problem, use a location
* on external storage (see {@link #setDestinationUri(Uri)}.
*/
public static class Request {
private Uri mUri;
private CharSequence mTitle;
private CharSequence mDescription;
private boolean mShowNotification = true;
private String mPackageName;
private String mMD5;
private int mSourceType;
private String mMimeType = Constants.MIMETYPE_APK;
private int mDestination = Impl.DESTINATION_EXTERNAL;
private String mIconUrl;
/**
* @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")) {
throw new IllegalArgumentException("Can only download HTTP URIs: " + uri);
}
mUri = uri;
}
/**
* Set the download destination
*/
public Request setDestination(int dest) {
mDestination = dest;
return this;
}
/**
* Set the title of this download, to be displayed in notifications (if enabled). If no
* title is given, a default one will be assigned based on the download filename, once the
* download starts.
* @return this object
*/
public Request setTitle(CharSequence title) {
mTitle = title;
return this;
}
public Request setSourceType(int sourceType) {
mSourceType = sourceType;
return this;
}
public Request setMimeType(String mimeType) {
mMimeType = mimeType;
return this;
}
/**
* Set a description of this download, to be displayed in notifications (if enabled)
* @return this object
*/
public Request setDescription(CharSequence description) {
mDescription = description;
return this;
}
/**
* Set the md5 code of the file
*/
public Request setMD5(String md5) {
mMD5 = md5;
return this;
}
/**
* Set the Package Name of the APK file.
* @param packageName
*/
public Request setPackageName(String packageName) {
mPackageName = packageName;
return this;
}
public Request setIconUrl(String url) {
mIconUrl = url;
return this;
}
/**
* Control whether a system notification is posted by the download manager while this
* download is running. If enabled, the download manager posts notifications about downloads
* through the system {@link android.app.NotificationManager}. By default, a notification is
* shown.
*
* If set to false, this requires the permission
* android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
*
* @param show whether the download manager should show a notification for this download.
* @return this object
*/
public Request setShowRunningNotification(boolean show) {
mShowNotification = show;
return this;
}
/**
* @return ContentValues to be passed to DownloadProvider.insert()
*/
ContentValues toContentValues(String packageName) {
ContentValues values = new ContentValues();
assert mUri != null;
values.put(Impl.COLUMN_URI, mUri.toString());
values.put(Impl.COLUMN_NOTIFICATION_PACKAGE, packageName);
values.put(Impl.COLUMN_MIME_TYPE, mMimeType);
values.put(Impl.COLUMN_NOTIFICATION_EXTRAS, mIconUrl);
values.put(Impl.COLUMN_SOURCE, mSourceType);
putIfNonNull(values, Impl.COLUMN_TITLE, mTitle);
putIfNonNull(values, Impl.COLUMN_DESCRIPTION, mDescription);
values.put(Impl.COLUMN_VISIBILITY,
mShowNotification ? Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
: Impl.VISIBILITY_HIDDEN);
if (mSourceType == Constants.DOWNLOAD_FROM_OTA
&& Constants.MIMETYPE_APK.equals(mMimeType)) {
values.put(Impl.COLUMN_VISIBILITY, Impl.VISIBILITY_VISIBLE);
}
return values;
}
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}
*/
public static final int ORDER_ASCENDING = 1;
/**
* Constant for use with {@link #orderBy}
*/
public static final int ORDER_DESCENDING = 2;
private long[] mIds = null;
private Integer mStatusFlags = null;
private String mOrderByColumn = Impl.COLUMN_LAST_MODIFICATION;
private int mOrderDirection = ORDER_DESCENDING;
/**
* 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;
}
/**
* 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
*/
public Query orderBy(String column, int direction) {
if (direction != ORDER_ASCENDING && direction != ORDER_DESCENDING) {
throw new IllegalArgumentException("Invalid direction: " + direction);
}
if (column.equals(Impl.COLUMN_LAST_MODIFICATION)) {
mOrderByColumn = Impl.COLUMN_LAST_MODIFICATION;
} else if (column.equals(Impl.COLUMN_TOTAL_BYTES)) {
mOrderByColumn = Impl.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("=", Impl.STATUS_PENDING));
}
if ((mStatusFlags & STATUS_RUNNING) != 0) {
parts.add(statusClause("=", Impl.STATUS_RUNNING));
}
if ((mStatusFlags & STATUS_PAUSED) != 0) {
parts.add(statusClause("=", Impl.STATUS_PAUSED_BY_APP));
parts.add(statusClause("=", Impl.STATUS_WAITING_TO_RETRY));
parts.add(statusClause("=", Impl.STATUS_WAITING_FOR_NETWORK));
parts.add(statusClause("=", Impl.STATUS_QUEUED_FOR_WIFI));
}
if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
parts.add(statusClause("=", Impl.STATUS_SUCCESS));
}
if ((mStatusFlags & STATUS_FAILED) != 0) {
parts.add("(" + statusClause(">=", 400)
+ " AND " + statusClause("<", 600) + ")");
}
selectionParts.add(joinStrings(" OR ", parts));
}
// only return rows which are not marked 'deleted = 1'
selectionParts.add(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 Impl.COLUMN_STATUS + operator + "'" + value + "'";
}
}
/**
* Implementation details
*
* Exposes constants used to interact with the download manager's content provider. The
* constants URI ... STATUS are the names of columns in the downloads table.
*
*/
public static final class Impl implements BaseColumns {
private Impl() {
}
/**
* An identifier for a particular download, unique across the system. Clients use this ID to
* make subsequent calls related to the download.
*/
public final static String COLUMN_ID = BaseColumns._ID;
/**
* The name of the column containing the URI of the data being downloaded.
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
public static final String COLUMN_URI = "uri";
/**
* The name of the column containing application-specific data.
* <P>Type: TEXT</P>
* <P>Owner can Init/Read/Write</P>
*/
public static final String COLUMN_APP_DATA = "entity";
/**
* The name of the column containing the filename that the initiating
* application recommends. When possible, the download manager will attempt
* to use this filename, or a variation, as the actual name for the file.
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
public static final String COLUMN_FILE_NAME_HINT = "hint";
/**
* The name of the column containing the filename where the downloaded data
* was actually stored.
* <P>Type: TEXT</P>
* <P>Owner can Read</P>
*/
public static final String COLUMN_DATA = "_data";
/**
* The name of the column containing the MIME type of the downloaded data.
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
public static final String COLUMN_MIME_TYPE = "mimetype";
/**
* The name of the column containing the flag that controls the destination
* of the download. See the DESTINATION_* constants for a list of legal values.
* <P>Type: INTEGER</P>
* <P>Owner can Init</P>
*/
public static final String COLUMN_DESTINATION = "destination";
/**
* The name of the column containing the flags that controls whether the
* download is displayed by the UI. See the VISIBILITY_* constants for
* a list of legal values.
* <P>Type: INTEGER</P>
* <P>Owner can Init/Read/Write</P>
*/
public static final String COLUMN_VISIBILITY = "visibility";
/**
* The name of the column containing the current control state of the download.
* Applications can write to this to control (pause/resume) the download.
* the CONTROL_* constants for a list of legal values.
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
public static final String COLUMN_CONTROL = "control";
/**
* The name of the column containing the current status of the download.
* Applications can read this to follow the progress of each download. See
* the STATUS_* constants for a list of legal values.
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
public static final String COLUMN_STATUS = "status";
/**
* The times of trying to get contact with server but failed
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
public static final String COLUMN_FAILED_CONNECTIONS = "numfailed";
/**
* The times of request meet the HTTP redirect directives
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
public static final String COLUMN_RETRY_AFTER_REDIRECT_COUNT = "redirectcount";
/**
* The column that is used for the downloads's ETag(Guarantee the file integrity)
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
public static final String COLUMN_ETAG = "etag";
/**
* The column that is used to remember where download request comes from
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
public static final String COLUMN_SOURCE = "source";
/**
* The column that is used for the initiating app's MD5
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
public static final String COLUMN_MD5 = "md5";
/**
* 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>
*/
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>
*/
public static final String COLUMN_NOTIFICATION_PACKAGE = "notificationpackage";
/**
* The name of the column containing the component name of the class that
* will receive notifications associated with the download. The
* package/class combination is passed to
* Intent.setClassName(String,String).
* <P>Type: TEXT</P>
* <P>Owner can Init/Read</P>
*/
public static final String COLUMN_NOTIFICATION_CLASS = "notificationclass";
/**
* If extras are specified when requesting a download they will be provided in the intent that
* is sent to the specified class and package when a download has finished.
* <P>Type: TEXT</P>
* <P>Owner can Init</P>
*/
public static final String COLUMN_NOTIFICATION_EXTRAS = "notificationextras";
/**
* The name of the column containing the total size of the file being
* downloaded.
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
public static final String COLUMN_TOTAL_BYTES = "total_bytes";
/**
* The name of the column containing the size of the part of the file that
* has been downloaded so far.
* <P>Type: INTEGER</P>
* <P>Owner can Read</P>
*/
public static final String COLUMN_CURRENT_BYTES = "current_bytes";
/**
* The name of the column where the initiating application can provided the
* title of this download. The title will be displayed ito the user in the
* list of downloads.
* <P>Type: TEXT</P>
* <P>Owner can Init/Read/Write</P>
*/
public static final String COLUMN_TITLE = "title";
/**
* The name of the column where the initiating application can provide the
* description of this download. The description will be displayed to the
* user in the list of downloads.
* <P>Type: TEXT</P>
* <P>Owner can Init/Read/Write</P>
*/
public static final String COLUMN_DESCRIPTION = "description";
/**
* Set to true if this download is deleted. It is completely removed from the database
* when MediaProvider database also deletes the metadata asociated with this downloaded file.
* <P>Type: BOOLEAN</P>
* <P>Owner can Read</P>
*/
public static final String COLUMN_DELETED = "deleted";
/**
* The package name of the APK file. This not necessary for other files.
*/
public static final String COLUMN_PACKAGE_NAME = "package_name";
/*
* Lists the destinations that an application can specify for a download.
*/
/**
* This download will be saved to the external storage. This is the
* default behavior, and should be used for any file that the user
* can freely access, copy, delete. Even with that destination,
* unencrypted DRM files are saved in secure internal storage.
* Downloads to the external destination only write files for which
* there is a registered handler. The resulting files are accessible
* by filename to all applications.
*/
public static final int DESTINATION_EXTERNAL = 0;
/**
* This download will be saved to the download manager's private
* partition. This is the behavior used by applications that want to
* download private files that are used and deleted soon after they
* get downloaded. All file types are allowed, and only the initiating
* application can access the file (indirectly through a content
* provider). This requires the
* android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED permission.
*/
public static final int DESTINATION_CACHE_PARTITION = 1;
/**
* This download will be saved to the download manager's private
* partition and will be purged as necessary to make space. This is
* for private files (similar to CACHE_PARTITION) that aren't deleted
* immediately after they are used, and are kept around by the download
* manager as long as space is available.
*/
public static final int DESTINATION_CACHE_PARTITION_PURGEABLE = 2;
/**
* 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 = 3;
/**
* 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;
/**
* This download is in the task waiting queue
*/
public static final int CONTROL_PENDING = 2;
/*
* Lists the states that the download manager can set on a download
* to notify applications of the download progress.
* The codes follow the HTTP families:<br>
* 1xx: informational<br>
* 2xx: success<br>
* 3xx: redirects (not used by the download manager)<br>
* 4xx: client errors<br>
* 5xx: server errors
*/
/**
* Returns whether the status is informational (i.e. 1xx).
*/
public static boolean isStatusInformational(int status) {
return (status >= 100 && status < 200);
}
/**
* 下载进行中
*/
public static boolean isStatusRunning(int status) {
return status == STATUS_RUNNING;
}
/**
* 下载等待中
*/
public static boolean isStatusPending(int status) {
return status == STATUS_PENDING
|| status == STATUS_PAUSED_BY_APP
|| status == STATUS_WAITING_TO_RETRY
|| status == STATUS_WAITING_FOR_NETWORK
|| status == STATUS_QUEUED_FOR_WIFI;
}
/**
* 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;
/**
* This download has successfully completed.
* Warning: there might be other status values that indicate success
* in the future.
* Use isSucccess() to capture the entire category.
*/
public static final int STATUS_SUCCESS = 200;
/**
* This downloaded apk has successfully installed.
*/
public static final int STATUS_INSTALLED = 260;
/**
* This request couldn't be parsed. This is also used when processing
* requests with unknown/unsupported URI schemes.
*/
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;
/**
* This download cannot be performed because the length cannot be
* determined accurately. This is the code for the HTTP error "Length
* Required", which is typically used when making requests that require
* a content length but don't have one, and it is also used in the
* client when a response is received whose length cannot be determined
* accurately (therefore making it impossible to know when a download
* completes).
*/
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 MD5 check error
*/
public static final int STATUS_FILE_MD5_ERROR = 486;
/**
* The lowest-valued error status that is not an actual HTTP status code.
*/
public static final int STATUS_MIN_ARTIFICIAL_ERROR_STATUS = 487;
/**
* 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;
/**
* This download has completed with an error.
* Warning: there will be other status values that indicate errors in
* the future. Use isStatusError() to capture the entire category.
*/
public static final int STATUS_UNKNOWN_ERROR = 491;
/**
* This download couldn't be completed because of a storage issue.
* Typically, that's because the filesystem is missing or full.
* Use the more specific {@link #STATUS_INSUFFICIENT_SPACE_ERROR}
* and {@link #STATUS_DEVICE_NOT_FOUND_ERROR} when appropriate.
*/
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;
/**
* The content:// URI to access downloads owned by the caller's UID.
*/
public static final Uri CONTENT_URI = Uri.parse("content://gfan_downloads/my_downloads");
}
}