1 /*
2  * Copyright (C) 2013 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.ui;
18 
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.Dialog;
22 import android.app.DialogFragment;
23 import android.app.DownloadManager;
24 import android.app.DownloadManager.Query;
25 import android.app.FragmentManager;
26 import android.content.ContentUris;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.Intent;
30 import android.database.Cursor;
31 import android.net.Uri;
32 import android.os.Bundle;
33 import android.provider.DocumentsContract;
34 import android.util.Log;
35 import android.widget.Toast;
36 
37 import com.android.providers.downloads.Constants;
38 import com.android.providers.downloads.MediaStoreDownloadsHelper;
39 import com.android.providers.downloads.OpenHelper;
40 import com.android.providers.downloads.RawDocumentsHelper;
41 
42 import libcore.io.IoUtils;
43 
44 /**
45  * Intercept all download clicks to provide special behavior. For example,
46  * PackageInstaller really wants raw file paths.
47  */
48 public class TrampolineActivity extends Activity {
49     private static final String TAG_PAUSED = "paused";
50     private static final String TAG_FAILED = "failed";
51 
52     private static final String KEY_ID = "id";
53     private static final String KEY_REASON = "reason";
54     private static final String KEY_SIZE = "size";
55 
56     @Override
onCreate(Bundle savedInstanceState)57     protected void onCreate(Bundle savedInstanceState) {
58         super.onCreate(savedInstanceState);
59 
60         Uri documentUri = getIntent().getData();
61         if (RawDocumentsHelper.isRawDocId(DocumentsContract.getDocumentId(documentUri))) {
62             if (!RawDocumentsHelper.startViewIntent(this, documentUri)) {
63                 Toast.makeText(this, R.string.download_no_application_title, Toast.LENGTH_SHORT)
64                         .show();
65             }
66             finish();
67             return;
68         }
69 
70         if (MediaStoreDownloadsHelper.isMediaStoreDownload(
71                 DocumentsContract.getDocumentId(documentUri))) {
72             final Intent intent = OpenHelper.buildViewIntentForMediaStoreDownload(
73                     this, documentUri);
74             if (intent == null || !OpenHelper.startViewIntent(this, intent)) {
75                 Toast.makeText(this, R.string.download_no_application_title, Toast.LENGTH_SHORT)
76                         .show();
77             }
78             finish();
79             return;
80         }
81 
82         final long id = ContentUris.parseId(documentUri);
83         final DownloadManager dm = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
84         dm.setAccessAllDownloads(true);
85 
86         final int status;
87         final int reason;
88         final long size;
89 
90         final Cursor cursor = dm.query(new Query().setFilterById(id));
91         try {
92             if (cursor.moveToFirst()) {
93                 status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS));
94                 reason = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON));
95                 size = cursor.getLong(
96                         cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
97             } else {
98                 Toast.makeText(this, R.string.dialog_file_missing_body, Toast.LENGTH_SHORT).show();
99                 finish();
100                 return;
101             }
102         } finally {
103             IoUtils.closeQuietly(cursor);
104         }
105 
106         Log.d(Constants.TAG, "Found " + id + " with status " + status + ", reason " + reason);
107         switch (status) {
108             case DownloadManager.STATUS_PENDING:
109             case DownloadManager.STATUS_RUNNING:
110                 sendRunningDownloadClickedBroadcast(id);
111                 finish();
112                 break;
113 
114             case DownloadManager.STATUS_PAUSED:
115                 if (reason == DownloadManager.PAUSED_QUEUED_FOR_WIFI) {
116                     PausedDialogFragment.show(getFragmentManager(), id, size);
117                 } else {
118                     sendRunningDownloadClickedBroadcast(id);
119                     finish();
120                 }
121                 break;
122 
123             case DownloadManager.STATUS_SUCCESSFUL:
124                 if (!OpenHelper.startViewIntent(this, id, 0)) {
125                     Toast.makeText(this, R.string.download_no_application_title, Toast.LENGTH_SHORT)
126                             .show();
127                 }
128                 finish();
129                 break;
130 
131             case DownloadManager.STATUS_FAILED:
132                 FailedDialogFragment.show(getFragmentManager(), id, reason);
133                 break;
134         }
135     }
136 
sendRunningDownloadClickedBroadcast(long id)137     private void sendRunningDownloadClickedBroadcast(long id) {
138         final Intent intent = new Intent(Constants.ACTION_LIST);
139         intent.setPackage(Constants.PROVIDER_PACKAGE_NAME);
140         intent.putExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS, new long[] { id });
141         sendBroadcast(intent);
142     }
143 
144     public static class PausedDialogFragment extends DialogFragment {
show(FragmentManager fm, long id, long size)145         public static void show(FragmentManager fm, long id, long size) {
146             final PausedDialogFragment dialog = new PausedDialogFragment();
147             final Bundle args = new Bundle();
148             args.putLong(KEY_ID, id);
149             args.putLong(KEY_SIZE, size);
150             dialog.setArguments(args);
151             dialog.show(fm, TAG_PAUSED);
152         }
153 
154         @Override
onCreateDialog(Bundle savedInstanceState)155         public Dialog onCreateDialog(Bundle savedInstanceState) {
156             final Context context = getActivity();
157 
158             final DownloadManager dm = (DownloadManager) context.getSystemService(
159                     Context.DOWNLOAD_SERVICE);
160             dm.setAccessAllDownloads(true);
161 
162             final long id = getArguments().getLong(KEY_ID);
163             final long size = getArguments().getLong(KEY_SIZE);
164 
165             final AlertDialog.Builder builder = new AlertDialog.Builder(
166                     context, android.R.style.Theme_DeviceDefault_Light_Dialog_Alert);
167             builder.setTitle(R.string.dialog_title_queued_body);
168             builder.setMessage(R.string.dialog_queued_body);
169 
170             final Long maxSize = DownloadManager.getMaxBytesOverMobile(context);
171             if (maxSize != null && size > maxSize) {
172                 // When we have a max size, we have no choice
173                 builder.setPositiveButton(R.string.keep_queued_download, null);
174             } else {
175                 // Give user the choice of starting now
176                 builder.setPositiveButton(R.string.start_now_download,
177                         new DialogInterface.OnClickListener() {
178                             @Override
179                             public void onClick(DialogInterface dialog, int which) {
180                                 dm.forceDownload(id);
181                             }
182                         });
183             }
184 
185             builder.setNegativeButton(
186                     R.string.remove_download, new DialogInterface.OnClickListener() {
187                         @Override
188                         public void onClick(DialogInterface dialog, int which) {
189                             dm.remove(id);
190                         }
191                     });
192 
193             return builder.create();
194         }
195 
196         @Override
onDismiss(DialogInterface dialog)197         public void onDismiss(DialogInterface dialog) {
198             super.onDismiss(dialog);
199             final Activity activity = getActivity();
200             if (activity != null) {
201                 activity.finish();
202             }
203         }
204     }
205 
206     public static class FailedDialogFragment extends DialogFragment {
show(FragmentManager fm, long id, int reason)207         public static void show(FragmentManager fm, long id, int reason) {
208             final FailedDialogFragment dialog = new FailedDialogFragment();
209             final Bundle args = new Bundle();
210             args.putLong(KEY_ID, id);
211             args.putInt(KEY_REASON, reason);
212             dialog.setArguments(args);
213             dialog.show(fm, TAG_FAILED);
214         }
215 
216         @Override
onCreateDialog(Bundle savedInstanceState)217         public Dialog onCreateDialog(Bundle savedInstanceState) {
218             final Context context = getActivity();
219 
220             final DownloadManager dm = (DownloadManager) context.getSystemService(
221                     Context.DOWNLOAD_SERVICE);
222             dm.setAccessAllDownloads(true);
223 
224             final long id = getArguments().getLong(KEY_ID);
225             final int reason = getArguments().getInt(KEY_REASON);
226 
227             final AlertDialog.Builder builder = new AlertDialog.Builder(
228                     context, android.R.style.Theme_DeviceDefault_Light_Dialog_Alert);
229             builder.setTitle(R.string.dialog_title_not_available);
230 
231             switch (reason) {
232                 case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
233                     builder.setMessage(R.string.dialog_file_already_exists);
234                     break;
235                 case DownloadManager.ERROR_INSUFFICIENT_SPACE:
236                     builder.setMessage(R.string.dialog_insufficient_space_on_cache);
237                     break;
238                 case DownloadManager.ERROR_DEVICE_NOT_FOUND:
239                     builder.setMessage(R.string.dialog_media_not_found);
240                     break;
241                 case DownloadManager.ERROR_CANNOT_RESUME:
242                     builder.setMessage(R.string.dialog_cannot_resume);
243                     break;
244                 default:
245                     builder.setMessage(R.string.dialog_failed_body);
246             }
247 
248             builder.setNegativeButton(
249                     R.string.delete_download, new DialogInterface.OnClickListener() {
250                         @Override
251                         public void onClick(DialogInterface dialog, int which) {
252                             dm.remove(id);
253                         }
254                     });
255 
256             builder.setPositiveButton(
257                     R.string.retry_download, new DialogInterface.OnClickListener() {
258                         @Override
259                         public void onClick(DialogInterface dialog, int which) {
260                             dm.restartDownload(id);
261                         }
262                     });
263 
264             return builder.create();
265         }
266 
267         @Override
onDismiss(DialogInterface dialog)268         public void onDismiss(DialogInterface dialog) {
269             super.onDismiss(dialog);
270             final Activity activity = getActivity();
271             if (activity != null) {
272                 activity.finish();
273             }
274         }
275     }
276 }
277