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