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