Как запросить несколько загрузок с помощью Download Manager в Android 2.3.3 - PullRequest
7 голосов
/ 23 января 2012

Как запросить менеджер загрузок Android для загрузки нескольких файлов одновременно.Также я хотел бы знать каждый статус загрузки файла.

Ответы [ 4 ]

9 голосов
/ 23 января 2012

Запросить первый.

Затем запросите второй.

Затем запросите третий.

Продолжайте по мере необходимости.

Если вы загружаете "одновременно", это не ваше дело, и вы не можете это контролировать. Они будут загружаться, когда DownloadManager решит загрузить их, что может быть одновременно или нет.

1 голос
/ 02 апреля 2015
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;
        }
    }
}
0 голосов
/ 02 апреля 2015
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_";
    }
  }
}
0 голосов
/ 02 апреля 2015

открытый класс DownloadManager {private static final String 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;
        }
    }
}

}

...