1c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey/*
2c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey * Copyright (C) 2012 The Android Open Source Project
3c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey *
4c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey * you may not use this file except in compliance with the License.
6c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey * You may obtain a copy of the License at
7c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey *
8c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey *
10c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
11c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey * See the License for the specific language governing permissions and
14c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey * limitations under the License.
15c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey */
16c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
17c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeypackage com.android.providers.downloads;
18c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
19169ab531ca6bb2f43ed18fe2b03f66c808f12b81Jeff Sharkeyimport static android.app.DownloadManager.COLUMN_LOCAL_FILENAME;
20c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport static android.app.DownloadManager.COLUMN_LOCAL_URI;
21c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport static android.app.DownloadManager.COLUMN_MEDIA_TYPE;
22c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport static android.app.DownloadManager.COLUMN_URI;
23c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport static android.provider.Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI;
248ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkeyimport static com.android.providers.downloads.Constants.TAG;
25c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
26c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport android.app.DownloadManager;
278ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkeyimport android.content.ActivityNotFoundException;
28c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport android.content.ContentUris;
29c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport android.content.Context;
30c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport android.content.Intent;
31c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport android.database.Cursor;
32c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport android.net.Uri;
33c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeyimport android.provider.Downloads.Impl.RequestHeaders;
348ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkeyimport android.util.Log;
35c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
365cff4ecb10e89e4fb39cd9e39b8753a31efbe3ccJeff Sharkeyimport java.io.File;
375cff4ecb10e89e4fb39cd9e39b8753a31efbe3ccJeff Sharkey
38c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkeypublic class OpenHelper {
39c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey    /**
408ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey     * Build and start an {@link Intent} to view the download with given ID,
418ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey     * handling subtleties around installing packages.
42c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey     */
438ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey    public static boolean startViewIntent(Context context, long id, int intentFlags) {
448ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey        final Intent intent = OpenHelper.buildViewIntent(context, id);
458ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey        if (intent == null) {
468ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey            Log.w(TAG, "No intent built for " + id);
478ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey            return false;
488ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey        }
498ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey
508ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey        intent.addFlags(intentFlags);
518ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey        try {
528ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey            context.startActivity(intent);
538ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey            return true;
548ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey        } catch (ActivityNotFoundException e) {
558ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey            Log.w(TAG, "Failed to start " + intent + ": " + e);
568ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey            return false;
578ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey        }
588ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey    }
598ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey
608ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey    /**
618ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey     * Build an {@link Intent} to view the download with given ID, handling
628ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey     * subtleties around installing packages.
638ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey     */
648ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey    private static Intent buildViewIntent(Context context, long id) {
65c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        final DownloadManager downManager = (DownloadManager) context.getSystemService(
66c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                Context.DOWNLOAD_SERVICE);
67c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        downManager.setAccessAllDownloads(true);
68c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
69c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        final Cursor cursor = downManager.query(new DownloadManager.Query().setFilterById(id));
70c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        try {
71c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            if (!cursor.moveToFirst()) {
728ec87ea5a5c191554d6205d4c779768664b1724bJeff Sharkey                return null;
73c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            }
74c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
75c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            final Uri localUri = getCursorUri(cursor, COLUMN_LOCAL_URI);
765cff4ecb10e89e4fb39cd9e39b8753a31efbe3ccJeff Sharkey            final File file = getCursorFile(cursor, COLUMN_LOCAL_FILENAME);
77169ab531ca6bb2f43ed18fe2b03f66c808f12b81Jeff Sharkey            String mimeType = getCursorString(cursor, COLUMN_MEDIA_TYPE);
785cff4ecb10e89e4fb39cd9e39b8753a31efbe3ccJeff Sharkey            mimeType = DownloadDrmHelper.getOriginalMimeType(context, file, mimeType);
79c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
80c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            final Intent intent = new Intent(Intent.ACTION_VIEW);
81c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
82c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            if ("application/vnd.android.package-archive".equals(mimeType)) {
83c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                // PackageInstaller doesn't like content URIs, so open file
84c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                intent.setDataAndType(localUri, mimeType);
85c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
86c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                // Also splice in details about where it came from
87c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                final Uri remoteUri = getCursorUri(cursor, COLUMN_URI);
88c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                intent.putExtra(Intent.EXTRA_ORIGINATING_URI, remoteUri);
89c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                intent.putExtra(Intent.EXTRA_REFERRER, getRefererUri(context, id));
9046bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver                intent.putExtra(Intent.EXTRA_ORIGINATING_UID, getOriginatingUid(context, id));
91c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            } else if ("file".equals(localUri.getScheme())) {
9204c1c2afb7481e7fb9b66f96023c79d19cad8c90Jeff Sharkey                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
9304c1c2afb7481e7fb9b66f96023c79d19cad8c90Jeff Sharkey                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
94c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                intent.setDataAndType(
95c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                        ContentUris.withAppendedId(ALL_DOWNLOADS_CONTENT_URI, id), mimeType);
96c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            } else {
9704c1c2afb7481e7fb9b66f96023c79d19cad8c90Jeff Sharkey                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
98c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                intent.setDataAndType(localUri, mimeType);
99c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            }
100c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
101c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            return intent;
102c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        } finally {
103c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            cursor.close();
104c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        }
105c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey    }
106c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
107c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey    private static Uri getRefererUri(Context context, long id) {
108c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        final Uri headersUri = Uri.withAppendedPath(
109c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                ContentUris.withAppendedId(ALL_DOWNLOADS_CONTENT_URI, id),
110c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                RequestHeaders.URI_SEGMENT);
111c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        final Cursor headers = context.getContentResolver()
112c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                .query(headersUri, null, null, null, null);
113c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        try {
114c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            while (headers.moveToNext()) {
115c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                final String header = getCursorString(headers, RequestHeaders.COLUMN_HEADER);
116c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                if ("Referer".equalsIgnoreCase(header)) {
117c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                    return getCursorUri(headers, RequestHeaders.COLUMN_VALUE);
118c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey                }
119c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            }
120c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        } finally {
121c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey            headers.close();
122c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        }
123c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        return null;
124c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey    }
125c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
12646bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver    private static int getOriginatingUid(Context context, long id) {
12746bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver        final Uri uri = ContentUris.withAppendedId(ALL_DOWNLOADS_CONTENT_URI, id);
12846bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver        final Cursor cursor = context.getContentResolver().query(uri, new String[]{Constants.UID},
12946bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver                null, null, null);
13046bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver        if (cursor != null) {
13146bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver            try {
13246bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver                if (cursor.moveToFirst()) {
13346bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver                    return cursor.getInt(cursor.getColumnIndexOrThrow(Constants.UID));
13446bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver                }
13546bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver            } finally {
13646bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver                cursor.close();
13746bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver            }
13846bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver        }
13946bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver        return -1;
14046bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver    }
14146bb7dd18c9b092d352d76ab44a4e52951941b2cBen Gruver
142c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey    private static String getCursorString(Cursor cursor, String column) {
143c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        return cursor.getString(cursor.getColumnIndexOrThrow(column));
144c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey    }
145c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
146c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey    private static Uri getCursorUri(Cursor cursor, String column) {
147c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey        return Uri.parse(getCursorString(cursor, column));
148c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey    }
149c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey
1505cff4ecb10e89e4fb39cd9e39b8753a31efbe3ccJeff Sharkey    private static File getCursorFile(Cursor cursor, String column) {
1515cff4ecb10e89e4fb39cd9e39b8753a31efbe3ccJeff Sharkey        return new File(cursor.getString(cursor.getColumnIndexOrThrow(column)));
1525cff4ecb10e89e4fb39cd9e39b8753a31efbe3ccJeff Sharkey    }
153c0622bf896c1af62b0e69b18cd84c7de3b67beb3Jeff Sharkey}
154