AttachmentActionHandler.java revision 47ca4e2a4c2d7387a7dd8d1925e2512acc553eab
1/* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.mail.browse; 19 20import android.app.DialogFragment; 21import android.app.Fragment; 22import android.app.FragmentManager; 23import android.app.FragmentTransaction; 24import android.content.ActivityNotFoundException; 25import android.content.ContentValues; 26import android.content.Context; 27import android.content.DialogInterface; 28import android.content.Intent; 29import android.net.Uri; 30import android.os.Handler; 31import android.os.Parcelable; 32 33import com.android.mail.providers.Attachment; 34import com.android.mail.providers.UIProvider.AttachmentColumns; 35import com.android.mail.providers.UIProvider.AttachmentDestination; 36import com.android.mail.providers.UIProvider.AttachmentState; 37import com.android.mail.utils.LogTag; 38import com.android.mail.utils.LogUtils; 39import com.android.mail.utils.Utils; 40 41import java.util.ArrayList; 42import java.util.List; 43 44public class AttachmentActionHandler { 45 private static final String PROGRESS_FRAGMENT_TAG = "attachment-progress"; 46 47 private Attachment mAttachment; 48 private boolean mDialogClosed; 49 50 private final AttachmentCommandHandler mCommandHandler; 51 private final AttachmentViewInterface mView; 52 private final Context mContext; 53 private final Handler mHandler; 54 private FragmentManager mFragmentManager; 55 56 private static final String LOG_TAG = LogTag.getLogTag(); 57 58 public AttachmentActionHandler(Context context, AttachmentViewInterface view) { 59 mCommandHandler = new AttachmentCommandHandler(context); 60 mView = view; 61 mContext = context; 62 mDialogClosed = false; 63 mHandler = new Handler(); 64 } 65 66 public void initialize(FragmentManager fragmentManager) { 67 mFragmentManager = fragmentManager; 68 } 69 70 public void setAttachment(Attachment attachment) { 71 mAttachment = attachment; 72 } 73 74 public void showAttachment(int destination) { 75 // If the caller requested that this attachments be saved to the external storage, we should 76 // verify that the it was saved there. 77 if (mAttachment.isPresentLocally() && 78 (destination == AttachmentDestination.CACHE || 79 mAttachment.destination == destination)) { 80 mView.viewAttachment(); 81 } else { 82 showDownloadingDialog(destination); 83 startDownloadingAttachment(destination); 84 } 85 } 86 87 public void showAndDownloadAttachments() { 88 final List<Attachment> attachments = mView.getAttachments(); 89 90 for (final Attachment attachment : attachments) { 91 if (!attachment.isPresentLocally()) { 92 startDownloadingAttachment(attachment, AttachmentDestination.CACHE); 93 } 94 } 95 96 mView.viewAttachment(); 97 } 98 99 public void startDownloadingAttachment(int destination) { 100 startDownloadingAttachment(mAttachment, destination); 101 } 102 103 private void startDownloadingAttachment(Attachment attachment, int destination) { 104 final ContentValues params = new ContentValues(2); 105 params.put(AttachmentColumns.STATE, AttachmentState.DOWNLOADING); 106 params.put(AttachmentColumns.DESTINATION, destination); 107 108 mCommandHandler.sendCommand(attachment.uri, params); 109 } 110 111 public void cancelAttachment() { 112 final ContentValues params = new ContentValues(1); 113 params.put(AttachmentColumns.STATE, AttachmentState.NOT_SAVED); 114 115 mCommandHandler.sendCommand(mAttachment.uri, params); 116 } 117 118 public void startRedownloadingAttachment(Attachment attachment) { 119 final ContentValues params = new ContentValues(2); 120 params.put(AttachmentColumns.STATE, AttachmentState.REDOWNLOADING); 121 params.put(AttachmentColumns.DESTINATION, attachment.destination); 122 123 mCommandHandler.sendCommand(attachment.uri, params); 124 } 125 126 /** 127 * Displays a loading dialog to be used for downloading attachments. 128 * Must be called on the UI thread. 129 */ 130 private void showDownloadingDialog(int destination) { 131 final FragmentTransaction ft = mFragmentManager.beginTransaction(); 132 final Fragment prev = mFragmentManager.findFragmentByTag(PROGRESS_FRAGMENT_TAG); 133 if (prev != null) { 134 ft.remove(prev); 135 } 136 ft.addToBackStack(null); 137 138 // Create and show the dialog. 139 final DialogFragment newFragment = AttachmentProgressDialogFragment.newInstance( 140 mAttachment, destination); 141 newFragment.show(ft, PROGRESS_FRAGMENT_TAG); 142 } 143 144 public void onDismiss(DialogInterface dialog) { 145 mDialogClosed = true; 146 } 147 148 public void onCancel(DialogInterface dialog) { 149 cancelAttachment(); 150 } 151 152 /** 153 * Update progress-related views. Will also trigger a view intent if a progress dialog was 154 * previously brought up (by tapping 'View') and the download has now finished. 155 */ 156 public void updateStatus(boolean loaderResult) { 157 final boolean showProgress = mAttachment.shouldShowProgress(); 158 159 final AttachmentProgressDialogFragment dialog = (AttachmentProgressDialogFragment) 160 mFragmentManager.findFragmentByTag(PROGRESS_FRAGMENT_TAG); 161 if (dialog != null && dialog.isShowingDialogForAttachment(mAttachment)) { 162 dialog.setProgress(mAttachment.downloadedSize); 163 164 // We don't want the progress bar to switch back to indeterminate mode after 165 // have been in determinate progress mode. 166 final boolean indeterminate = !showProgress && dialog.isIndeterminate(); 167 dialog.setIndeterminate(indeterminate); 168 169 if (loaderResult && !mAttachment.isDownloading()) { 170 mHandler.post(new Runnable() { 171 @Override 172 public void run() { 173 dialog.dismiss(); 174 } 175 }); 176 } 177 178 if (mAttachment.state == AttachmentState.SAVED) { 179 mView.viewAttachment(); 180 } 181 } else { 182 mView.updateProgress(showProgress); 183 } 184 185 // Call on update status for the view so that it can do some specific things. 186 mView.onUpdateStatus(); 187 } 188 189 public boolean isProgressDialogVisible() { 190 final Fragment dialog = mFragmentManager.findFragmentByTag(PROGRESS_FRAGMENT_TAG); 191 return dialog != null && dialog.isVisible(); 192 } 193 194 public void shareAttachment() { 195 if (mAttachment.contentUri == null) { 196 return; 197 } 198 199 Intent intent = new Intent(Intent.ACTION_SEND); 200 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION 201 | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 202 203 final Uri uri = Utils.normalizeUri(mAttachment.contentUri); 204 intent.putExtra(Intent.EXTRA_STREAM, uri); 205 intent.setType(Utils.normalizeMimeType(mAttachment.contentType)); 206 207 try { 208 mContext.startActivity(intent); 209 } catch (ActivityNotFoundException e) { 210 // couldn't find activity for SEND intent 211 LogUtils.e(LOG_TAG, "Couldn't find Activity for intent", e); 212 } 213 } 214 215 public void shareAttachments(ArrayList<Parcelable> uris) { 216 Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); 217 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION 218 | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 219 220 intent.setType("image/*"); 221 intent.putParcelableArrayListExtra( 222 Intent.EXTRA_STREAM, uris); 223 224 try { 225 mContext.startActivity(intent); 226 } catch (ActivityNotFoundException e) { 227 // couldn't find activity for SEND_MULTIPLE intent 228 LogUtils.e(LOG_TAG, "Couldn't find Activity for intent", e); 229 } 230 } 231 232 /** 233 * Returns true if this is the first time this method has been called after 234 * the progress dialog was closed. Necessary to prevent a brief flicker where the 235 * cancel button would appear after closing the progress dialog. Subsequent 236 * calls to this method will return false until the progress dialog is 237 * opened again. 238 * @return true if this is the first time this method has been called 239 * since a progress dialog was visible. false otherwise. 240 */ 241 public boolean dialogJustClosed() { 242 final boolean closed = mDialogClosed; 243 mDialogClosed = false; 244 return closed; 245 } 246} 247