Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eca77fcd authored by Steve Howard's avatar Steve Howard
Browse files

Support new URI structure for download provider.

I'm changing the URI structure for the download provider a bit.  The
download provider will now support two views into its data:

* content://downloads/my_downloads... will basically be the current
  view, which is limited to downloads owned by the calling UID
* content://downloads/all_downloads... will include all downloads in
  the system, but will require special permission

In addition to making things more clear, this change will allow for
granting URI permissions to individual downloads via the
/all_downloads/... URI.

This change includes the framework changes necessary to support the
new structure.  The bulk of the work will be in the DownloadProvider
code itself.

In addition, this change makes DownloadManager return a content URI
rather than a file URI for /cache downloads.  This avoids any
confusion in clients, which wouldn't be able to open the file
directly, and better supports granting permissions to viewers.

Change-Id: Ie548b927817ac774111990dd0c9d26aaf979d1ea
parent 9909b948
Loading
Loading
Loading
Loading
+41 −11
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.net;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.CursorWrapper;
@@ -536,12 +537,12 @@ public class DownloadManager {
         * @param projection the projection to pass to ContentResolver.query()
         * @return the Cursor returned by ContentResolver.query()
         */
        Cursor runQuery(ContentResolver resolver, String[] projection) {
            Uri uri = Downloads.CONTENT_URI;
        Cursor runQuery(ContentResolver resolver, String[] projection, Uri baseUri) {
            Uri uri = baseUri;
            List<String> selectionParts = new ArrayList<String>();

            if (mId != null) {
                uri = Uri.withAppendedPath(uri, mId.toString());
                uri = ContentUris.withAppendedId(uri, mId);
            }

            if (mStatusFlags != null) {
@@ -597,6 +598,7 @@ public class DownloadManager {

    private ContentResolver mResolver;
    private String mPackageName;
    private Uri mBaseUri = Downloads.Impl.CONTENT_URI;

    /**
     * @hide
@@ -606,6 +608,19 @@ public class DownloadManager {
        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;
        }
    }

    /**
     * Enqueue a new download.  The download will start automatically once the download manager is
     * ready to execute it and connectivity is available.
@@ -642,11 +657,11 @@ public class DownloadManager {
     * COLUMN_* constants.
     */
    public Cursor query(Query query) {
        Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS);
        Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS, mBaseUri);
        if (underlyingCursor == null) {
            return null;
        }
        return new CursorTranslator(underlyingCursor);
        return new CursorTranslator(underlyingCursor, mBaseUri);
    }

    /**
@@ -690,9 +705,8 @@ public class DownloadManager {
    /**
     * Get the DownloadProvider URI for the download with the given ID.
     */
    private Uri getDownloadUri(long id) {
        Uri downloadUri = Uri.withAppendedPath(Downloads.CONTENT_URI, Long.toString(id));
        return downloadUri;
    Uri getDownloadUri(long id) {
        return ContentUris.withAppendedId(mBaseUri, id);
    }

    /**
@@ -702,8 +716,11 @@ public class DownloadManager {
     * underlying data.
     */
    private static class CursorTranslator extends CursorWrapper {
        public CursorTranslator(Cursor cursor) {
        private Uri mBaseUri;

        public CursorTranslator(Cursor cursor, Uri baseUri) {
            super(cursor);
            mBaseUri = baseUri;
        }

        @Override
@@ -799,13 +816,26 @@ public class DownloadManager {
            }

            assert column.equals(COLUMN_LOCAL_URI);
            String localUri = getUnderlyingString(Downloads._DATA);
            return getLocalUri();
        }

        private String getLocalUri() {
            String localUri = getUnderlyingString(Downloads.Impl._DATA);
            if (localUri == null) {
                return null;
            }

            long destinationType = getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION);
            if (destinationType == Downloads.Impl.DESTINATION_FILE_URI) {
                // return file URI for external download
                return Uri.fromFile(new File(localUri)).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
+10 −3
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ public final class Downloads {
     * @hide
     */
    public static final Uri CONTENT_URI =
        Uri.parse("content://downloads/download");
        Uri.parse("content://downloads/my_downloads");

    /**
     * Broadcast Action: this is sent by the download manager to the app
@@ -637,10 +637,17 @@ public final class Downloads {
                "android.permission.DOWNLOAD_WITHOUT_NOTIFICATION";

        /**
         * The content:// URI for the data table in the provider
         * The content:// URI to access downloads owned by the caller's UID.
         */
        public static final Uri CONTENT_URI =
            Uri.parse("content://downloads/download");
                Uri.parse("content://downloads/my_downloads");

        /**
         * The content URI for accessing all downloads across all UIDs (requires the
         * ACCESS_ALL_DOWNLOADS permission).
         */
        public static final Uri ALL_DOWNLOADS_CONTENT_URI =
                Uri.parse("content://downloads/all_downloads");

        /**
         * Broadcast Action: this is sent by the download manager to the app