summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/downloads/DownloadStorageProvider.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/DownloadStorageProvider.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/DownloadStorageProvider.java')
-rw-r--r--src/com/android/providers/downloads/DownloadStorageProvider.java87
1 files changed, 80 insertions, 7 deletions
diff --git a/src/com/android/providers/downloads/DownloadStorageProvider.java b/src/com/android/providers/downloads/DownloadStorageProvider.java
index 7268c5c6..d982f2a1 100644
--- a/src/com/android/providers/downloads/DownloadStorageProvider.java
+++ b/src/com/android/providers/downloads/DownloadStorageProvider.java
@@ -18,6 +18,7 @@ package com.android.providers.downloads;
import android.app.DownloadManager;
import android.app.DownloadManager.Query;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
@@ -26,16 +27,20 @@ import android.database.MatrixCursor.RowBuilder;
import android.graphics.Point;
import android.os.Binder;
import android.os.CancellationSignal;
+import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
import android.text.TextUtils;
+import android.webkit.MimeTypeMap;
import libcore.io.IoUtils;
+import java.io.File;
import java.io.FileNotFoundException;
+import java.io.IOException;
/**
* Presents a {@link DocumentsContract} view of {@link DownloadManager}
@@ -83,7 +88,8 @@ public class DownloadStorageProvider extends DocumentsProvider {
final RowBuilder row = result.newRow();
row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT);
row.add(Root.COLUMN_ROOT_TYPE, Root.ROOT_TYPE_SHORTCUT);
- row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_RECENTS);
+ row.add(Root.COLUMN_FLAGS,
+ Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_RECENTS | Root.FLAG_SUPPORTS_CREATE);
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher_download);
row.add(Root.COLUMN_TITLE, getContext().getString(R.string.root_downloads));
row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
@@ -91,6 +97,40 @@ public class DownloadStorageProvider extends DocumentsProvider {
}
@Override
+ public String createDocument(String docId, String mimeType, String displayName)
+ throws FileNotFoundException {
+ final File parent = Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_DOWNLOADS);
+
+ // Delegate to real provider
+ final long token = Binder.clearCallingIdentity();
+ try {
+ displayName = removeExtension(mimeType, displayName);
+ File file = new File(parent, addExtension(mimeType, displayName));
+
+ // If conflicting file, try adding counter suffix
+ int n = 0;
+ while (file.exists() && n++ < 32) {
+ file = new File(parent, addExtension(mimeType, displayName + " (" + n + ")"));
+ }
+
+ try {
+ if (!file.createNewFile()) {
+ throw new IllegalStateException("Failed to touch " + file);
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to touch " + file + ": " + e);
+ }
+
+ return Long.toString(mDm.addCompletedDownload(
+ file.getName(), file.getName(), false, mimeType, file.getAbsolutePath(), 0L,
+ false, true));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public void deleteDocument(String docId) throws FileNotFoundException {
// Delegate to real provider
final long token = Binder.clearCallingIdentity();
@@ -209,14 +249,12 @@ public class DownloadStorageProvider extends DocumentsProvider {
@Override
public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
throws FileNotFoundException {
- if (!"r".equals(mode)) {
- throw new IllegalArgumentException("Downloads are read-only");
- }
-
// Delegate to real provider
final long token = Binder.clearCallingIdentity();
try {
- return mDm.openDownloadedFile(Long.parseLong(docId));
+ final long id = Long.parseLong(docId);
+ final ContentResolver resolver = getContext().getContentResolver();
+ return resolver.openFileDescriptor(mDm.getDownloadUri(id), mode, signal);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -234,7 +272,8 @@ public class DownloadStorageProvider extends DocumentsProvider {
final RowBuilder row = result.newRow();
row.add(Document.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
- row.add(Document.COLUMN_FLAGS, Document.FLAG_DIR_PREFERS_LAST_MODIFIED);
+ row.add(Document.COLUMN_FLAGS,
+ Document.FLAG_DIR_PREFERS_LAST_MODIFIED | Document.FLAG_DIR_SUPPORTS_CREATE);
}
private void includeDownloadFromCursor(MatrixCursor result, Cursor cursor) {
@@ -288,6 +327,12 @@ public class DownloadStorageProvider extends DocumentsProvider {
flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
}
+ final int allowWrite = cursor.getInt(
+ cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ALLOW_WRITE));
+ if (allowWrite != 0) {
+ flags |= Document.FLAG_SUPPORTS_WRITE;
+ }
+
final long lastModified = cursor.getLong(
cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP));
@@ -300,4 +345,32 @@ public class DownloadStorageProvider extends DocumentsProvider {
row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
row.add(Document.COLUMN_FLAGS, flags);
}
+
+ /**
+ * Remove file extension from name, but only if exact MIME type mapping
+ * exists. This means we can reapply the extension later.
+ */
+ private static String removeExtension(String mimeType, String name) {
+ final int lastDot = name.lastIndexOf('.');
+ if (lastDot >= 0) {
+ final String extension = name.substring(lastDot + 1);
+ final String nameMime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ if (mimeType.equals(nameMime)) {
+ return name.substring(0, lastDot);
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Add file extension to name, but only if exact MIME type mapping exists.
+ */
+ private static String addExtension(String mimeType, String name) {
+ final String extension = MimeTypeMap.getSingleton()
+ .getExtensionFromMimeType(mimeType);
+ if (extension != null) {
+ return name + "." + extension;
+ }
+ return name;
+ }
}