summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/downloads/DownloadProvider.java
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2013-09-23 14:21:55 -0700
committerJeff Sharkey <jsharkey@android.com>2013-09-23 14:25:50 -0700
commitc067c8be21dc4a6dc5f49b2b1aed7f91aab47063 (patch)
treea1ed113bae539117db084f51f579ed78fbd19d3b /src/com/android/providers/downloads/DownloadProvider.java
parente0b9b881187362aea61249952a913d794834b728 (diff)
downloadandroid_packages_providers_DownloadProvider-c067c8be21dc4a6dc5f49b2b1aed7f91aab47063.tar.gz
android_packages_providers_DownloadProvider-c067c8be21dc4a6dc5f49b2b1aed7f91aab47063.tar.bz2
android_packages_providers_DownloadProvider-c067c8be21dc4a6dc5f49b2b1aed7f91aab47063.zip
Allow saving to Downloads.
Add column to mark downloads as being writable, and allow documents to be created under Downloads backend. Update database when writing is finished, and generate unique filenames when they already exist. Check canonical path on incoming _DATA paths. Bug: 10667164, 10892621, 10893268 Change-Id: I8c203b96ff042a895b58686903fcd07fc755a00f
Diffstat (limited to 'src/com/android/providers/downloads/DownloadProvider.java')
-rw-r--r--src/com/android/providers/downloads/DownloadProvider.java55
1 files changed, 46 insertions, 9 deletions
diff --git a/src/com/android/providers/downloads/DownloadProvider.java b/src/com/android/providers/downloads/DownloadProvider.java
index e0b5842d..999134f0 100644
--- a/src/com/android/providers/downloads/DownloadProvider.java
+++ b/src/com/android/providers/downloads/DownloadProvider.java
@@ -35,7 +35,9 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
+import android.os.Handler;
import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.OnCloseListener;
import android.os.Process;
import android.os.SELinux;
import android.provider.BaseColumns;
@@ -49,6 +51,8 @@ import com.android.internal.util.IndentingPrintWriter;
import com.google.android.collect.Maps;
import com.google.common.annotations.VisibleForTesting;
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -69,7 +73,7 @@ public final class DownloadProvider extends ContentProvider {
/** Database filename */
private static final String DB_NAME = "downloads.db";
/** Current database version */
- private static final int DB_VERSION = 108;
+ private static final int DB_VERSION = 109;
/** Name of table in the database */
private static final String DB_TABLE = "downloads";
@@ -166,6 +170,8 @@ public final class DownloadProvider extends ContentProvider {
private static final List<String> downloadManagerColumnsList =
Arrays.asList(DownloadManager.UNDERLYING_COLUMNS);
+ private Handler mHandler;
+
/** The database that lies underneath this content provider */
private SQLiteOpenHelper mOpenHelper = null;
@@ -319,6 +325,11 @@ public final class DownloadProvider extends ContentProvider {
"INTEGER NOT NULL DEFAULT 1");
break;
+ case 109:
+ addColumn(db, DB_TABLE, Downloads.Impl.COLUMN_ALLOW_WRITE,
+ "BOOLEAN NOT NULL DEFAULT 0");
+ break;
+
default:
throw new IllegalStateException("Don't know how to upgrade to " + version);
}
@@ -432,6 +443,8 @@ public final class DownloadProvider extends ContentProvider {
mSystemFacade = new RealSystemFacade(getContext());
}
+ mHandler = new Handler();
+
mOpenHelper = new DatabaseHelper(getContext());
// Initialize the system uid
mSystemUid = Process.SYSTEM_UID;
@@ -590,6 +603,7 @@ public final class DownloadProvider extends ContentProvider {
filteredValues.put(Downloads.Impl.COLUMN_CURRENT_BYTES, 0);
copyInteger(Downloads.Impl.COLUMN_MEDIA_SCANNED, values, filteredValues);
copyString(Downloads.Impl._DATA, values, filteredValues);
+ copyBoolean(Downloads.Impl.COLUMN_ALLOW_WRITE, values, filteredValues);
} else {
filteredValues.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING);
filteredValues.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1);
@@ -784,6 +798,7 @@ public final class DownloadProvider extends ContentProvider {
values.remove(Downloads.Impl.COLUMN_ALLOW_METERED);
values.remove(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI);
values.remove(Downloads.Impl.COLUMN_MEDIA_SCANNED);
+ values.remove(Downloads.Impl.COLUMN_ALLOW_WRITE);
Iterator<Map.Entry<String, Object>> iterator = values.valueSet().iterator();
while (iterator.hasNext()) {
String key = iterator.next().getKey();
@@ -1162,13 +1177,15 @@ public final class DownloadProvider extends ContentProvider {
* Remotely opens a file
*/
@Override
- public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+ public ParcelFileDescriptor openFile(final Uri uri, String mode) throws FileNotFoundException {
if (Constants.LOGVV) {
logVerboseOpenFileInfo(uri, mode);
}
- Cursor cursor = query(uri, new String[] {"_data"}, null, null, null);
+ final Cursor cursor = query(uri, new String[] {
+ Downloads.Impl._DATA, Downloads.Impl.COLUMN_ALLOW_WRITE }, null, null, null);
String path;
+ boolean allowWrite;
try {
int count = (cursor != null) ? cursor.getCount() : 0;
if (count != 1) {
@@ -1181,10 +1198,9 @@ public final class DownloadProvider extends ContentProvider {
cursor.moveToFirst();
path = cursor.getString(0);
+ allowWrite = cursor.getInt(1) != 0;
} finally {
- if (cursor != null) {
- cursor.close();
- }
+ IoUtils.closeQuietly(cursor);
}
if (path == null) {
@@ -1193,12 +1209,33 @@ public final class DownloadProvider extends ContentProvider {
if (!Helpers.isFilenameValid(path, mDownloadsDataDir)) {
throw new FileNotFoundException("Invalid filename: " + path);
}
- if (!"r".equals(mode)) {
+ if (!allowWrite && !"r".equals(mode)) {
throw new FileNotFoundException("Bad mode for " + uri + ": " + mode);
}
- ParcelFileDescriptor ret = ParcelFileDescriptor.open(new File(path),
- ParcelFileDescriptor.MODE_READ_ONLY);
+ final File file = new File(path);
+
+ ParcelFileDescriptor ret;
+ if ("r".equals(mode)) {
+ ret = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+ } else {
+ try {
+ // When finished writing, update size and timestamp
+ ret = ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode),
+ mHandler, new OnCloseListener() {
+ @Override
+ public void onClose(IOException e) {
+ final ContentValues values = new ContentValues();
+ values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, file.length());
+ values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION,
+ System.currentTimeMillis());
+ update(uri, values, null, null);
+ }
+ });
+ } catch (IOException e) {
+ throw new FileNotFoundException("Failed to open for writing: " + e);
+ }
+ }
if (ret == null) {
if (Constants.LOGV) {