Home | History | Annotate | Download | only in downloads
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.providers.downloads;
     18 
     19 import static android.app.DownloadManager.COLUMN_LOCAL_FILENAME;
     20 import static android.app.DownloadManager.COLUMN_LOCAL_URI;
     21 import static android.app.DownloadManager.COLUMN_MEDIA_TYPE;
     22 import static android.app.DownloadManager.COLUMN_URI;
     23 import static android.provider.Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI;
     24 import static com.android.providers.downloads.Constants.TAG;
     25 
     26 import android.app.DownloadManager;
     27 import android.content.ActivityNotFoundException;
     28 import android.content.ContentUris;
     29 import android.content.Context;
     30 import android.content.Intent;
     31 import android.database.Cursor;
     32 import android.net.Uri;
     33 import android.os.StrictMode;
     34 import android.provider.DocumentsContract;
     35 import android.provider.Downloads.Impl.RequestHeaders;
     36 import android.util.Log;
     37 
     38 import java.io.File;
     39 
     40 public class OpenHelper {
     41     /**
     42      * Build and start an {@link Intent} to view the download with given ID,
     43      * handling subtleties around installing packages.
     44      */
     45     public static boolean startViewIntent(Context context, long id, int intentFlags) {
     46         final Intent intent = OpenHelper.buildViewIntent(context, id);
     47         if (intent == null) {
     48             Log.w(TAG, "No intent built for " + id);
     49             return false;
     50         }
     51 
     52         intent.addFlags(intentFlags);
     53         try {
     54             StrictMode.disableDeathOnFileUriExposure();
     55             context.startActivity(intent);
     56             return true;
     57         } catch (ActivityNotFoundException e) {
     58             Log.w(TAG, "Failed to start " + intent + ": " + e);
     59             return false;
     60         } finally {
     61             StrictMode.enableDeathOnFileUriExposure();
     62         }
     63     }
     64 
     65     /**
     66      * Build an {@link Intent} to view the download with given ID, handling
     67      * subtleties around installing packages.
     68      */
     69     private static Intent buildViewIntent(Context context, long id) {
     70         final DownloadManager downManager = (DownloadManager) context.getSystemService(
     71                 Context.DOWNLOAD_SERVICE);
     72         downManager.setAccessAllDownloads(true);
     73         downManager.setAccessFilename(true);
     74 
     75         final Cursor cursor = downManager.query(new DownloadManager.Query().setFilterById(id));
     76         try {
     77             if (!cursor.moveToFirst()) {
     78                 return null;
     79             }
     80 
     81             final Uri localUri = getCursorUri(cursor, COLUMN_LOCAL_URI);
     82             final File file = getCursorFile(cursor, COLUMN_LOCAL_FILENAME);
     83             String mimeType = getCursorString(cursor, COLUMN_MEDIA_TYPE);
     84             mimeType = DownloadDrmHelper.getOriginalMimeType(context, file, mimeType);
     85 
     86             final Uri documentUri = DocumentsContract.buildDocumentUri(
     87                     Constants.STORAGE_AUTHORITY, String.valueOf(id));
     88 
     89             final Intent intent = new Intent(Intent.ACTION_VIEW);
     90 
     91             if ("application/vnd.android.package-archive".equals(mimeType)) {
     92                 // PackageInstaller doesn't like content URIs, so open file
     93                 intent.setDataAndType(localUri, mimeType);
     94 
     95                 // Also splice in details about where it came from
     96                 final Uri remoteUri = getCursorUri(cursor, COLUMN_URI);
     97                 intent.putExtra(Intent.EXTRA_ORIGINATING_URI, remoteUri);
     98                 intent.putExtra(Intent.EXTRA_REFERRER, getRefererUri(context, id));
     99                 intent.putExtra(Intent.EXTRA_ORIGINATING_UID, getOriginatingUid(context, id));
    100             } else {
    101                 intent.setDataAndType(documentUri, mimeType);
    102                 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
    103                         | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    104             }
    105 
    106             return intent;
    107         } finally {
    108             cursor.close();
    109         }
    110     }
    111 
    112     private static Uri getRefererUri(Context context, long id) {
    113         final Uri headersUri = Uri.withAppendedPath(
    114                 ContentUris.withAppendedId(ALL_DOWNLOADS_CONTENT_URI, id),
    115                 RequestHeaders.URI_SEGMENT);
    116         final Cursor headers = context.getContentResolver()
    117                 .query(headersUri, null, null, null, null);
    118         try {
    119             while (headers.moveToNext()) {
    120                 final String header = getCursorString(headers, RequestHeaders.COLUMN_HEADER);
    121                 if ("Referer".equalsIgnoreCase(header)) {
    122                     return getCursorUri(headers, RequestHeaders.COLUMN_VALUE);
    123                 }
    124             }
    125         } finally {
    126             headers.close();
    127         }
    128         return null;
    129     }
    130 
    131     private static int getOriginatingUid(Context context, long id) {
    132         final Uri uri = ContentUris.withAppendedId(ALL_DOWNLOADS_CONTENT_URI, id);
    133         final Cursor cursor = context.getContentResolver().query(uri, new String[]{Constants.UID},
    134                 null, null, null);
    135         if (cursor != null) {
    136             try {
    137                 if (cursor.moveToFirst()) {
    138                     return cursor.getInt(cursor.getColumnIndexOrThrow(Constants.UID));
    139                 }
    140             } finally {
    141                 cursor.close();
    142             }
    143         }
    144         return -1;
    145     }
    146 
    147     private static String getCursorString(Cursor cursor, String column) {
    148         return cursor.getString(cursor.getColumnIndexOrThrow(column));
    149     }
    150 
    151     private static Uri getCursorUri(Cursor cursor, String column) {
    152         return Uri.parse(getCursorString(cursor, column));
    153     }
    154 
    155     private static File getCursorFile(Cursor cursor, String column) {
    156         return new File(cursor.getString(cursor.getColumnIndexOrThrow(column)));
    157     }
    158 }
    159