View file downloads through DownloadsProvider.
Jeff Sharkey [Mon, 16 Apr 2012 21:29:04 +0000 (14:29 -0700)]
When viewing file://-style downloads, open through DownloadsProvider
so that FLAG_GRANT_READ_URI_PERMISSION works.  Add support for
OpenableColumns to support external apps probing for metadata.

Bug: 6343461
Change-Id: I630405406321ea1871c62cbcded55a4ee024ef6e

src/com/android/providers/downloads/DownloadProvider.java
ui/src/com/android/providers/downloads/ui/DownloadList.java

index 3efdf63..4a3844f 100644 (file)
@@ -38,8 +38,10 @@ import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.provider.Downloads;
+import android.provider.OpenableColumns;
 import android.util.Log;
 
+import com.google.android.collect.Maps;
 import com.google.common.annotations.VisibleForTesting;
 
 import java.io.File;
@@ -47,6 +49,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -135,14 +138,24 @@ public final class DownloadProvider extends ContentProvider {
         Downloads.Impl.COLUMN_FILE_NAME_HINT,
         Downloads.Impl.COLUMN_MEDIAPROVIDER_URI,
         Downloads.Impl.COLUMN_DELETED,
+        OpenableColumns.DISPLAY_NAME,
+        OpenableColumns.SIZE,
     };
 
-    private static HashSet<String> sAppReadableColumnsSet;
+    private static final HashSet<String> sAppReadableColumnsSet;
+    private static final HashMap<String, String> sColumnsMap;
+
     static {
         sAppReadableColumnsSet = new HashSet<String>();
         for (int i = 0; i < sAppReadableColumnsArray.length; ++i) {
             sAppReadableColumnsSet.add(sAppReadableColumnsArray[i]);
         }
+
+        sColumnsMap = Maps.newHashMap();
+        sColumnsMap.put(OpenableColumns.DISPLAY_NAME,
+                Downloads.Impl.COLUMN_TITLE + " AS " + OpenableColumns.DISPLAY_NAME);
+        sColumnsMap.put(OpenableColumns.SIZE,
+                Downloads.Impl.COLUMN_TOTAL_BYTES + " AS " + OpenableColumns.SIZE);
     }
     private static final List<String> downloadManagerColumnsList =
             Arrays.asList(DownloadManager.UNDERLYING_COLUMNS);
@@ -440,10 +453,12 @@ public final class DownloadProvider extends ContentProvider {
     public String getType(final Uri uri) {
         int match = sURIMatcher.match(uri);
         switch (match) {
-            case MY_DOWNLOADS: {
+            case MY_DOWNLOADS:
+            case ALL_DOWNLOADS: {
                 return DOWNLOAD_LIST_TYPE;
             }
-            case MY_DOWNLOADS_ID: {
+            case MY_DOWNLOADS_ID:
+            case ALL_DOWNLOADS_ID: {
                 return DOWNLOAD_TYPE;
             }
             case PUBLIC_DOWNLOAD_ID: {
@@ -827,7 +842,7 @@ public final class DownloadProvider extends ContentProvider {
 
         if (shouldRestrictVisibility()) {
             if (projection == null) {
-                projection = sAppReadableColumnsArray;
+                projection = sAppReadableColumnsArray.clone();
             } else {
                 // check the validity of the columns in projection 
                 for (int i = 0; i < projection.length; ++i) {
@@ -838,6 +853,13 @@ public final class DownloadProvider extends ContentProvider {
                     }
                 }
             }
+
+            for (int i = 0; i < projection.length; i++) {
+                final String newColumn = sColumnsMap.get(projection[i]);
+                if (newColumn != null) {
+                    projection[i] = newColumn;
+                }
+            }
         }
 
         if (Constants.LOGVV) {
index 09573c6..281426a 100644 (file)
@@ -50,7 +50,6 @@ import android.widget.ExpandableListView.OnChildClickListener;
 import android.widget.ListView;
 import android.widget.Toast;
 
-import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -500,7 +499,8 @@ public class DownloadList extends Activity {
      * Send an Intent to open the download currently pointed to by the given cursor.
      */
     private void openCurrentDownload(Cursor cursor) {
-        Uri localUri = Uri.parse(cursor.getString(mLocalUriColumnId));
+        final long id = cursor.getInt(mIdColumnId);
+        final Uri localUri = Uri.parse(cursor.getString(mLocalUriColumnId));
         try {
             getContentResolver().openFileDescriptor(localUri, "r").close();
         } catch (FileNotFoundException exc) {
@@ -512,8 +512,19 @@ public class DownloadList extends Activity {
             // close() failed, not a problem
         }
 
+        final Uri viewUri;
+        final String mimeType = cursor.getString(mMediaTypeColumnId);
+        if ("application/vnd.android.package-archive".equals(mimeType)) {
+            // PackageInstaller doesn't like content URIs, so open file
+            viewUri = localUri;
+        } else if ("file".equals(localUri.getScheme())) {
+            viewUri = ContentUris.withAppendedId(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, id);
+        } else {
+            viewUri = localUri;
+        }
+
         Intent intent = new Intent(Intent.ACTION_VIEW);
-        intent.setDataAndType(localUri, cursor.getString(mMediaTypeColumnId));
+        intent.setDataAndType(viewUri, mimeType);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
         try {
             startActivity(intent);
@@ -729,10 +740,11 @@ public class DownloadList extends Activity {
             intent.setAction(Intent.ACTION_SEND_MULTIPLE);
             ArrayList<Parcelable> attachments = new ArrayList<Parcelable>();
             ArrayList<String> mimeTypes = new ArrayList<String>();
-            for (SelectionObjAttrs item : mSelectedIds.values()) {
-                String fileName = item.getFileName();
-                String mimeType = item.getMimeType();
-                attachments.add(Uri.fromFile(new File(fileName)));
+            for (Map.Entry<Long, SelectionObjAttrs> item : mSelectedIds.entrySet()) {
+                final Uri uri = ContentUris.withAppendedId(
+                        Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, item.getKey());
+                final String mimeType = item.getValue().getMimeType();
+                attachments.add(uri);
                 mimeTypes.add(mimeType);
             }
             intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachments);
@@ -740,16 +752,20 @@ public class DownloadList extends Activity {
         } else {
             // get the entry
             // since there is ONLY one entry in this, we can do the following
-            for (SelectionObjAttrs item : mSelectedIds.values()) {
+            for (Map.Entry<Long, SelectionObjAttrs> item : mSelectedIds.entrySet()) {
+                final Uri uri = ContentUris.withAppendedId(
+                        Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI, item.getKey());
+                final String mimeType = item.getValue().getMimeType();
                 intent.setAction(Intent.ACTION_SEND);
-                intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(item.getFileName())));
-                intent.setType(item.getMimeType());
+                intent.putExtra(Intent.EXTRA_STREAM, uri);
+                intent.setType(mimeType);
             }
         }
         Intent intentNew = Intent.createChooser(intent, getText(R.string.download_share_dialog));
         startActivity(intent);
         return true;
     }
+
     private String findCommonMimeType(ArrayList<String> mimeTypes) {
         // are all mimeypes the same?
         String str = findCommonString(mimeTypes);