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
This commit is contained in:
@@ -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,11 +816,24 @@ 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;
|
||||
}
|
||||
return Uri.fromFile(new File(localUri)).toString();
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user