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