Home | History | Annotate | Download | only in browse
      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 
     18 package com.android.mail.browse;
     19 
     20 
     21 import android.app.DialogFragment;
     22 import android.app.Fragment;
     23 import android.app.FragmentManager;
     24 import android.app.FragmentTransaction;
     25 import android.content.ActivityNotFoundException;
     26 import android.content.ContentValues;
     27 import android.content.Context;
     28 import android.content.Intent;
     29 import android.net.Uri;
     30 import android.os.Handler;
     31 import android.os.Parcelable;
     32 
     33 import com.android.mail.providers.Attachment;
     34 import com.android.mail.providers.Message;
     35 import com.android.mail.providers.UIProvider;
     36 import com.android.mail.providers.UIProvider.AttachmentColumns;
     37 import com.android.mail.providers.UIProvider.AttachmentContentValueKeys;
     38 import com.android.mail.providers.UIProvider.AttachmentDestination;
     39 import com.android.mail.providers.UIProvider.AttachmentState;
     40 import com.android.mail.utils.LogTag;
     41 import com.android.mail.utils.LogUtils;
     42 import com.android.mail.utils.Utils;
     43 
     44 import java.util.ArrayList;
     45 
     46 public class AttachmentActionHandler {
     47     private static final String PROGRESS_FRAGMENT_TAG = "attachment-progress";
     48 
     49     private String mAccount;
     50     private Message mMessage;
     51     private Attachment mAttachment;
     52 
     53     private final AttachmentCommandHandler mCommandHandler;
     54     private final AttachmentViewInterface mView;
     55     private final Context mContext;
     56     private final Handler mHandler;
     57     private FragmentManager mFragmentManager;
     58     private boolean mViewOnFinish;
     59 
     60     private static final String LOG_TAG = LogTag.getLogTag();
     61 
     62     private static OptionHandler sOptionHandler = new OptionHandler();
     63 
     64     public AttachmentActionHandler(Context context, AttachmentViewInterface view) {
     65         mCommandHandler = new AttachmentCommandHandler(context);
     66         mView = view;
     67         mContext = context;
     68         mHandler = new Handler();
     69         mViewOnFinish = true;
     70     }
     71 
     72     public void initialize(FragmentManager fragmentManager) {
     73         mFragmentManager = fragmentManager;
     74     }
     75 
     76     public void setAccount(String account) {
     77         mAccount = account;
     78     }
     79 
     80     public void setMessage(Message message) {
     81         mMessage = message;
     82     }
     83 
     84     public void setAttachment(Attachment attachment) {
     85         mAttachment = attachment;
     86     }
     87 
     88     public void setViewOnFinish(boolean viewOnFinish) {
     89         mViewOnFinish = viewOnFinish;
     90     }
     91 
     92     public void showAttachment(int destination) {
     93         if (mView == null) {
     94             return;
     95         }
     96 
     97         // If the caller requested that this attachments be saved to the external storage, we should
     98         // verify that the it was saved there.
     99         if (mAttachment.isPresentLocally() &&
    100                 (destination == AttachmentDestination.CACHE ||
    101                         mAttachment.destination == destination)) {
    102             mView.viewAttachment();
    103         } else {
    104             showDownloadingDialog();
    105             startDownloadingAttachment(destination);
    106         }
    107     }
    108 
    109     /**
    110      * Start downloading the full size attachment set with
    111      * {@link #setAttachment(Attachment)} immediately.
    112      */
    113     public void startDownloadingAttachment(int destination) {
    114         startDownloadingAttachment(destination, UIProvider.AttachmentRendition.BEST, 0, false);
    115     }
    116 
    117     public void startDownloadingAttachment(
    118             int destination, int rendition, int additionalPriority, boolean delayDownload) {
    119         startDownloadingAttachment(
    120                 mAttachment, destination, rendition, additionalPriority, delayDownload);
    121     }
    122 
    123     private void startDownloadingAttachment(
    124             Attachment attachment, int destination, int rendition, int additionalPriority,
    125             boolean delayDownload) {
    126         final ContentValues params = new ContentValues(5);
    127         params.put(AttachmentColumns.STATE, AttachmentState.DOWNLOADING);
    128         params.put(AttachmentColumns.DESTINATION, destination);
    129         params.put(AttachmentContentValueKeys.RENDITION, rendition);
    130         params.put(AttachmentContentValueKeys.ADDITIONAL_PRIORITY, additionalPriority);
    131         params.put(AttachmentContentValueKeys.DELAY_DOWNLOAD, delayDownload);
    132 
    133         mCommandHandler.sendCommand(attachment.uri, params);
    134     }
    135 
    136     public void cancelAttachment() {
    137         final ContentValues params = new ContentValues(1);
    138         params.put(AttachmentColumns.STATE, AttachmentState.NOT_SAVED);
    139 
    140         mCommandHandler.sendCommand(mAttachment.uri, params);
    141     }
    142 
    143     public void startRedownloadingAttachment(Attachment attachment) {
    144         final ContentValues params = new ContentValues(2);
    145         params.put(AttachmentColumns.STATE, AttachmentState.REDOWNLOADING);
    146         params.put(AttachmentColumns.DESTINATION, attachment.destination);
    147 
    148         mCommandHandler.sendCommand(attachment.uri, params);
    149     }
    150 
    151     /**
    152      * Displays a loading dialog to be used for downloading attachments.
    153      * Must be called on the UI thread.
    154      */
    155     public void showDownloadingDialog() {
    156         final FragmentTransaction ft = mFragmentManager.beginTransaction();
    157         final Fragment prev = mFragmentManager.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
    158         if (prev != null) {
    159             ft.remove(prev);
    160         }
    161         ft.addToBackStack(null);
    162 
    163          // Create and show the dialog.
    164         final DialogFragment newFragment = AttachmentProgressDialogFragment.newInstance(
    165                 mAttachment);
    166         newFragment.show(ft, PROGRESS_FRAGMENT_TAG);
    167     }
    168 
    169     /**
    170      * Update progress-related views. Will also trigger a view intent if a progress dialog was
    171      * previously brought up (by tapping 'View') and the download has now finished.
    172      */
    173     public void updateStatus(boolean loaderResult) {
    174         if (mView == null) {
    175             return;
    176         }
    177 
    178         final boolean showProgress = mAttachment.shouldShowProgress();
    179 
    180         final AttachmentProgressDialogFragment dialog = (AttachmentProgressDialogFragment)
    181                 mFragmentManager.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
    182         if (dialog != null && dialog.isShowingDialogForAttachment(mAttachment)) {
    183             dialog.setProgress(mAttachment.downloadedSize);
    184 
    185             // We don't want the progress bar to switch back to indeterminate mode after
    186             // have been in determinate progress mode.
    187             final boolean indeterminate = !showProgress && dialog.isIndeterminate();
    188             dialog.setIndeterminate(indeterminate);
    189 
    190             if (loaderResult && mAttachment.isDownloadFinishedOrFailed()) {
    191                 mHandler.post(new Runnable() {
    192                     @Override
    193                     public void run() {
    194                         dialog.dismiss();
    195                     }
    196                 });
    197             }
    198 
    199             if (mAttachment.state == AttachmentState.SAVED && mViewOnFinish) {
    200                 mView.viewAttachment();
    201             }
    202         } else {
    203             mView.updateProgress(showProgress);
    204         }
    205 
    206         // Call on update status for the view so that it can do some specific things.
    207         mView.onUpdateStatus();
    208     }
    209 
    210     public boolean isProgressDialogVisible() {
    211         final Fragment dialog = mFragmentManager.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
    212         return dialog != null && dialog.isVisible();
    213     }
    214 
    215     public void shareAttachment() {
    216         if (mAttachment.contentUri == null) {
    217             return;
    218         }
    219 
    220         Intent intent = new Intent(Intent.ACTION_SEND);
    221         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
    222                 | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    223 
    224         final Uri uri = Utils.normalizeUri(mAttachment.contentUri);
    225         intent.putExtra(Intent.EXTRA_STREAM, uri);
    226         intent.setType(Utils.normalizeMimeType(mAttachment.getContentType()));
    227 
    228         try {
    229             mContext.startActivity(intent);
    230         } catch (ActivityNotFoundException e) {
    231             // couldn't find activity for SEND intent
    232             LogUtils.e(LOG_TAG, "Couldn't find Activity for intent", e);
    233         }
    234     }
    235 
    236     public void shareAttachments(ArrayList<Parcelable> uris) {
    237         Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
    238         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
    239                 | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    240 
    241         intent.setType("image/*");
    242         intent.putParcelableArrayListExtra(
    243                 Intent.EXTRA_STREAM, uris);
    244 
    245         try {
    246             mContext.startActivity(intent);
    247         } catch (ActivityNotFoundException e) {
    248             // couldn't find activity for SEND_MULTIPLE intent
    249             LogUtils.e(LOG_TAG, "Couldn't find Activity for intent", e);
    250         }
    251     }
    252 
    253     public static void setOptionHandler(OptionHandler handler) {
    254         sOptionHandler = handler;
    255     }
    256 
    257     public boolean shouldShowExtraOption1(final String accountType, final String mimeType) {
    258         return (sOptionHandler != null) && sOptionHandler.shouldShowExtraOption1(
    259                 accountType, mimeType);
    260     }
    261 
    262     public void handleOption1() {
    263         if (sOptionHandler == null) {
    264             return;
    265         }
    266         sOptionHandler.handleOption1(mContext, mAccount, mMessage, mAttachment, mFragmentManager);
    267     }
    268 
    269     /**
    270      * A default, no-op option class. Override this and set it globally with
    271      * {@link AttachmentActionHandler#setOptionHandler(OptionHandler)}.<br>
    272      * <br>
    273      * Subclasses of this type will live pretty much forever, so really, really try to avoid
    274      * keeping any state as member variables in them.
    275      */
    276     public static class OptionHandler {
    277 
    278         public boolean shouldShowExtraOption1(String accountType, String mimeType) {
    279             return false;
    280         }
    281 
    282         public void handleOption1(Context context, String account, Message message,
    283                 Attachment attachment, FragmentManager fm) {
    284             // no-op
    285         }
    286     }
    287 }
    288