• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
getFragmentManager()63         FragmentManager getFragmentManager();
getMenuInflater()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 
MailPhotoViewController(ActivityInterface activity)87     public MailPhotoViewController(ActivityInterface activity) {
88         super(activity);
89         mMailActivity = activity;
90     }
91 
92     @Override
onCreate(Bundle savedInstanceState)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
onCreateOptionsMenu(Menu menu)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
onPrepareOptionsMenu(Menu menu)127     public boolean onPrepareOptionsMenu(Menu menu) {
128         updateActionItems();
129         return true;
130     }
131 
132     @Override
onOptionsItemSelected(MenuItem item)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
updateActionItems()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
updateActionBar()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
onFragmentVisible(PhotoViewFragment fragment)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
onCursorChanged(PhotoViewFragment fragment, Cursor cursor)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      */
updateProgressAndEmptyViews( final PhotoViewFragment fragment, final Attachment attachment)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      */
saveAttachment()312     private void saveAttachment() {
313         saveAttachment(getCurrentAttachment());
314     }
315 
316     /**
317      * Redownloads the attachment.
318      */
redownloadAttachment()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      */
saveAttachment(final Attachment attachment)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      */
saveAllAttachments()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      */
shareAttachment()361     private void shareAttachment() {
362         shareAttachment(getCurrentAttachment());
363     }
364 
365     /**
366      * Shares the attachment
367      * @param attachment the attachment to share
368      */
shareAttachment(final Attachment attachment)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      */
shareAllAttachments()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 
printAttachment()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      */
getCurrentAttachment()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 
getAllAttachments()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 
getMailActivity()437     public ActivityInterface getMailActivity() {
438         return mMailActivity;
439     }
440 }
441