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