Home | History | Annotate | Download | only in photo
      1 /*
      2  * Copyright (C) 2014 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.photo;
     19 
     20 import android.app.FragmentManager;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.database.Cursor;
     24 import android.os.Bundle;
     25 import android.os.Parcelable;
     26 import android.support.v4.print.PrintHelper;
     27 import android.view.Menu;
     28 import android.view.MenuInflater;
     29 import android.view.MenuItem;
     30 import android.view.View;
     31 import android.widget.ImageView;
     32 import android.widget.TextView;
     33 
     34 import com.android.ex.photo.ActionBarInterface;
     35 import com.android.ex.photo.PhotoViewController;
     36 import com.android.ex.photo.fragments.PhotoViewFragment;
     37 import com.android.ex.photo.views.ProgressBarWrapper;
     38 import com.android.mail.R;
     39 import com.android.mail.analytics.Analytics;
     40 import com.android.mail.browse.AttachmentActionHandler;
     41 import com.android.mail.print.PrintUtils;
     42 import com.android.mail.providers.Attachment;
     43 import com.android.mail.providers.Message;
     44 import com.android.mail.providers.UIProvider;
     45 import com.android.mail.utils.AttachmentUtils;
     46 import com.android.mail.utils.LogTag;
     47 import com.android.mail.utils.LogUtils;
     48 import com.android.mail.utils.Utils;
     49 import com.google.common.collect.Lists;
     50 
     51 import java.io.FileNotFoundException;
     52 import java.util.ArrayList;
     53 import java.util.List;
     54 
     55 /**
     56  * Derives from {@link PhotoViewController} to customize behavior
     57  * for UnifiedEmail's implementation of the photoviewer.
     58  * All of the work is actually performed here.
     59  */
     60 public class MailPhotoViewController extends PhotoViewController {
     61 
     62     public interface ActivityInterface extends PhotoViewController.ActivityInterface {
     63         FragmentManager getFragmentManager();
     64         MenuInflater getMenuInflater();
     65     }
     66 
     67     private final ActivityInterface mMailActivity;
     68 
     69     private static final String LOG_TAG = LogTag.getLogTag();
     70 
     71     private String mAccountType;
     72     private MenuItem mSaveItem;
     73     private MenuItem mSaveAllItem;
     74     private MenuItem mShareItem;
     75     private MenuItem mShareAllItem;
     76     private MenuItem mPrintItem;
     77     /**
     78      * Only for attachments that are currently downloading. Attachments that failed show the
     79      * retry button.
     80      */
     81     private MenuItem mDownloadAgainItem;
     82     private MenuItem mExtraOption1Item;
     83     protected AttachmentActionHandler mActionHandler;
     84     private Menu mMenu;
     85 
     86     private boolean mHideExtraOptionOne;
     87 
     88     public MailPhotoViewController(ActivityInterface activity) {
     89         super(activity);
     90         mMailActivity = activity;
     91     }
     92 
     93     @Override
     94     public void onCreate(Bundle savedInstanceState) {
     95         super.onCreate(savedInstanceState);
     96 
     97         mActionHandler = new AttachmentActionHandler(mMailActivity.getContext(), null);
     98         mActionHandler.initialize(mMailActivity.getFragmentManager());
     99 
    100         final Intent intent = mMailActivity.getIntent();
    101         mAccountType = intent.getStringExtra(MailPhotoViewActivity.EXTRA_ACCOUNT_TYPE);
    102         final String account = intent.getStringExtra(MailPhotoViewActivity.EXTRA_ACCOUNT);
    103         final Message msg = intent.getParcelableExtra(MailPhotoViewActivity.EXTRA_MESSAGE);
    104         mHideExtraOptionOne = intent.getBooleanExtra(
    105                 MailPhotoViewActivity.EXTRA_HIDE_EXTRA_OPTION_ONE, false);
    106         mActionHandler.setAccount(account);
    107         mActionHandler.setMessage(msg);
    108     }
    109 
    110     @Override
    111     public boolean onCreateOptionsMenu(Menu menu) {
    112         MenuInflater inflater = mMailActivity.getMenuInflater();
    113 
    114         inflater.inflate(R.menu.photo_view_menu, menu);
    115         mMenu = menu;
    116 
    117         mSaveItem = mMenu.findItem(R.id.menu_save);
    118         mSaveAllItem = mMenu.findItem(R.id.menu_save_all);
    119         mShareItem = mMenu.findItem(R.id.menu_share);
    120         mShareAllItem = mMenu.findItem(R.id.menu_share_all);
    121         mPrintItem = mMenu.findItem(R.id.menu_print);
    122         mDownloadAgainItem = mMenu.findItem(R.id.menu_download_again);
    123         mExtraOption1Item = mMenu.findItem(R.id.attachment_extra_option1);
    124 
    125         return true;
    126     }
    127 
    128     @Override
    129     public boolean onPrepareOptionsMenu(Menu menu) {
    130         updateActionItems();
    131         return true;
    132     }
    133 
    134     @Override
    135     public boolean onOptionsItemSelected(MenuItem item) {
    136         final int itemId = item.getItemId();
    137 
    138         Analytics.getInstance().sendMenuItemEvent(Analytics.EVENT_CATEGORY_MENU_ITEM, itemId,
    139                 "photo_viewer", 0);
    140 
    141         if (itemId == android.R.id.home) {
    142             // app icon in action bar clicked; go back to conversation
    143             mMailActivity.finish();
    144         } else if (itemId == R.id.menu_save) { // save the current photo
    145             saveAttachment();
    146         } else if (itemId == R.id.menu_save_all) { // save all of the photos
    147             saveAllAttachments();
    148         } else if (itemId == R.id.menu_share) { // share the current photo
    149             shareAttachment();
    150         } else if (itemId == R.id.menu_share_all) { // share all of the photos
    151             shareAllAttachments();
    152         } else if (itemId == R.id.menu_print) { // print the current photo
    153             printAttachment();
    154         } else if (itemId == R.id.menu_download_again) { // redownload the current photo
    155             redownloadAttachment();
    156         } else if (itemId == R.id.attachment_extra_option1) {
    157             mActionHandler.setAttachment(getCurrentAttachment());
    158             mActionHandler.handleOption1();
    159         } else {
    160             return super.onOptionsItemSelected(item);
    161         }
    162         return true;
    163     }
    164 
    165     /**
    166      * Updates the action items to tweak their visibility in case
    167      * there is functionality that is not relevant (eg, the Save
    168      * button should not appear if the photo has already been saved).
    169      */
    170     @Override
    171     public void updateActionItems() {
    172         final Attachment attachment = getCurrentAttachment();
    173 
    174         if (attachment != null && mSaveItem != null && mShareItem != null) {
    175             mSaveItem.setEnabled(!attachment.isDownloading()
    176                     && attachment.canSave() && !attachment.isSavedToExternal());
    177             final boolean canShare = attachment.canShare();
    178             mShareItem.setEnabled(canShare);
    179             mPrintItem.setEnabled(canShare);
    180             mDownloadAgainItem.setEnabled(attachment.canSave() && attachment.isDownloading());
    181             mExtraOption1Item.setVisible(!mHideExtraOptionOne &&
    182                     mActionHandler.shouldShowExtraOption1(mAccountType,
    183                             attachment.getContentType()));
    184         } else {
    185             if (mMenu != null) {
    186                 mMenu.setGroupEnabled(R.id.photo_view_menu_group, false);
    187             }
    188             return;
    189         }
    190 
    191         List<Attachment> attachments = getAllAttachments();
    192         if (attachments != null) {
    193             boolean enabled = false;
    194             for (final Attachment a : attachments) {
    195                 // If one attachment can be saved, enable save all
    196                 if (!a.isDownloading() && a.canSave() && !a.isSavedToExternal()) {
    197                     enabled = true;
    198                     break;
    199                 }
    200             }
    201             mSaveAllItem.setEnabled(enabled);
    202 
    203             // all attachments must be present to be able to share all
    204             enabled = true;
    205             for (final Attachment a : attachments) {
    206                 if (!a.canShare()) {
    207                     enabled = false;
    208                     break;
    209                 }
    210             }
    211             mShareAllItem.setEnabled(enabled);
    212         }
    213 
    214         // Turn off functionality that only works on JellyBean.
    215         if (!Utils.isRunningJellybeanOrLater()) {
    216             mShareItem.setVisible(false);
    217             mShareAllItem.setVisible(false);
    218         }
    219 
    220         // Turn off functionality that only works on KitKat.
    221         if (!Utils.isRunningKitkatOrLater()) {
    222             mPrintItem.setVisible(false);
    223         }
    224     }
    225 
    226 
    227     /**
    228      * Adjusts the activity title and subtitle to reflect the image name and size.
    229      */
    230     @Override
    231     public void updateActionBar() {
    232         super.updateActionBar();
    233 
    234         final Attachment attachment = getCurrentAttachment();
    235         final ActionBarInterface actionBar = mMailActivity.getActionBarInterface();
    236         final String size = AttachmentUtils.convertToHumanReadableSize(
    237                 mMailActivity.getContext(), attachment.size);
    238 
    239         // update the status
    240         // There are 3 states
    241         //      1. Saved, Attachment Size
    242         //      2. Saving...
    243         //      3. Default, Attachment Size
    244         if (attachment.isSavedToExternal()) {
    245             actionBar.setSubtitle(mMailActivity.getResources().getString(R.string.saved, size));
    246         } else if (attachment.isDownloading() &&
    247                 attachment.destination == UIProvider.AttachmentDestination.EXTERNAL) {
    248             actionBar.setSubtitle(mMailActivity.getResources().getString(R.string.saving));
    249         } else {
    250             actionBar.setSubtitle(size);
    251         }
    252         updateActionItems();
    253     }
    254 
    255     @Override
    256     public void onFragmentVisible(PhotoViewFragment fragment) {
    257         super.onFragmentVisible(fragment);
    258         final Attachment attachment = getCurrentAttachment();
    259         if (attachment.state == UIProvider.AttachmentState.PAUSED) {
    260             mActionHandler.setAttachment(attachment);
    261             mActionHandler.startDownloadingAttachment(attachment.destination);
    262         }
    263     }
    264 
    265     @Override
    266     public void onCursorChanged(PhotoViewFragment fragment, Cursor cursor) {
    267         super.onCursorChanged(fragment, cursor);
    268         updateProgressAndEmptyViews(fragment, new Attachment(cursor));
    269     }
    270 
    271     /**
    272      * Updates the empty views of the fragment based upon the current
    273      * state of the attachment.
    274      * @param fragment the current fragment
    275      */
    276     private void updateProgressAndEmptyViews(
    277             final PhotoViewFragment fragment, final Attachment attachment) {
    278         final ProgressBarWrapper progressBar = fragment.getPhotoProgressBar();
    279         final TextView emptyText = fragment.getEmptyText();
    280         final ImageView retryButton = fragment.getRetryButton();
    281 
    282         // update the progress
    283         if (attachment.shouldShowProgress()) {
    284             progressBar.setMax(attachment.size);
    285             progressBar.setProgress(attachment.downloadedSize);
    286             progressBar.setIndeterminate(false);
    287         } else if (fragment.isProgressBarNeeded()) {
    288             progressBar.setIndeterminate(true);
    289         }
    290 
    291         // If the download failed, show the empty text and retry button
    292         if (attachment.isDownloadFailed()) {
    293             emptyText.setText(R.string.photo_load_failed);
    294             emptyText.setVisibility(View.VISIBLE);
    295             retryButton.setVisibility(View.VISIBLE);
    296             retryButton.setOnClickListener(new View.OnClickListener() {
    297                 @Override
    298                 public void onClick(View view) {
    299                     redownloadAttachment();
    300                     emptyText.setVisibility(View.GONE);
    301                     retryButton.setVisibility(View.GONE);
    302                 }
    303             });
    304             progressBar.setVisibility(View.GONE);
    305         }
    306     }
    307 
    308     /**
    309      * Save the current attachment.
    310      */
    311     private void saveAttachment() {
    312         saveAttachment(getCurrentAttachment());
    313     }
    314 
    315     /**
    316      * Redownloads the attachment.
    317      */
    318     private void redownloadAttachment() {
    319         final Attachment attachment = getCurrentAttachment();
    320         if (attachment != null && attachment.canSave()) {
    321             // REDOWNLOADING command is only for attachments that are finished or failed.
    322             // For an attachment that is downloading (or paused in the DownloadManager), we need to
    323             // cancel it first.
    324             mActionHandler.setAttachment(attachment);
    325             mActionHandler.cancelAttachment();
    326             mActionHandler.startDownloadingAttachment(attachment.destination);
    327         }
    328     }
    329 
    330     /**
    331      * Saves the attachment.
    332      * @param attachment the attachment to save.
    333      */
    334     private void saveAttachment(final Attachment attachment) {
    335         if (attachment != null && attachment.canSave()) {
    336             mActionHandler.setAttachment(attachment);
    337             mActionHandler.startDownloadingAttachment(UIProvider.AttachmentDestination.EXTERNAL);
    338         }
    339     }
    340 
    341     /**
    342      * Save all of the attachments in the cursor.
    343      */
    344     private void saveAllAttachments() {
    345         Cursor cursor = getCursorAtProperPosition();
    346 
    347         if (cursor == null) {
    348             return;
    349         }
    350 
    351         int i = -1;
    352         while (cursor.moveToPosition(++i)) {
    353             saveAttachment(new Attachment(cursor));
    354         }
    355     }
    356 
    357     /**
    358      * Share the current attachment.
    359      */
    360     private void shareAttachment() {
    361         shareAttachment(getCurrentAttachment());
    362     }
    363 
    364     /**
    365      * Shares the attachment
    366      * @param attachment the attachment to share
    367      */
    368     private void shareAttachment(final Attachment attachment) {
    369         if (attachment != null) {
    370             mActionHandler.setAttachment(attachment);
    371             mActionHandler.shareAttachment();
    372         }
    373     }
    374 
    375     /**
    376      * Share all of the attachments in the cursor.
    377      */
    378     private void shareAllAttachments() {
    379         Cursor cursor = getCursorAtProperPosition();
    380 
    381         if (cursor == null) {
    382             return;
    383         }
    384 
    385         ArrayList<Parcelable> uris = new ArrayList<Parcelable>();
    386         int i = -1;
    387         while (cursor.moveToPosition(++i)) {
    388             uris.add(Utils.normalizeUri(new Attachment(cursor).contentUri));
    389         }
    390 
    391         mActionHandler.shareAttachments(uris);
    392     }
    393 
    394     private void printAttachment() {
    395         final Attachment attachment = getCurrentAttachment();
    396         final Context context = mMailActivity.getContext();
    397         final PrintHelper printHelper = new PrintHelper(context);
    398         try {
    399             printHelper.setScaleMode(PrintHelper.SCALE_MODE_FIT);
    400             printHelper.printBitmap(PrintUtils.buildPrintJobName(context, attachment.getName()),
    401                     attachment.contentUri);
    402         } catch (FileNotFoundException e) {
    403             // couldn't print a photo at the particular Uri. Should we notify the user?
    404             LogUtils.e(LOG_TAG, e, "Can't print photo");
    405         }
    406     }
    407 
    408     /**
    409      * Helper method to get the currently visible attachment.
    410      */
    411     protected Attachment getCurrentAttachment() {
    412         final Cursor cursor = getCursorAtProperPosition();
    413 
    414         if (cursor == null) {
    415             return null;
    416         }
    417 
    418         return new Attachment(cursor);
    419     }
    420 
    421     private List<Attachment> getAllAttachments() {
    422         final Cursor cursor = getCursor();
    423 
    424         if (cursor == null || cursor.isClosed() || !cursor.moveToFirst()) {
    425             return null;
    426         }
    427 
    428         List<Attachment> list = Lists.newArrayList();
    429         do {
    430             list.add(new Attachment(cursor));
    431         } while (cursor.moveToNext());
    432 
    433         return list;
    434     }
    435 
    436     public ActivityInterface getMailActivity() {
    437         return mMailActivity;
    438     }
    439 }
    440