MailPhotoViewController.java revision a00a413f293b73b8b6d16c0707d08f881fd92e1c
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
18package com.android.mail.photo;
19
20import android.app.FragmentManager;
21import android.content.Context;
22import android.content.Intent;
23import android.database.Cursor;
24import android.os.Bundle;
25import android.os.Parcelable;
26import android.support.v4.print.PrintHelper;
27import android.view.Menu;
28import android.view.MenuInflater;
29import android.view.MenuItem;
30import android.view.View;
31import android.widget.ImageView;
32import android.widget.TextView;
33
34import com.android.ex.photo.ActionBarInterface;
35import com.android.ex.photo.PhotoViewController;
36import com.android.ex.photo.fragments.PhotoViewFragment;
37import com.android.ex.photo.views.ProgressBarWrapper;
38import com.android.mail.R;
39import com.android.mail.analytics.Analytics;
40import com.android.mail.browse.AttachmentActionHandler;
41import com.android.mail.print.PrintUtils;
42import com.android.mail.providers.Attachment;
43import com.android.mail.providers.Message;
44import com.android.mail.providers.UIProvider;
45import com.android.mail.utils.AttachmentUtils;
46import com.android.mail.utils.LogTag;
47import com.android.mail.utils.LogUtils;
48import com.android.mail.utils.Utils;
49import com.google.common.collect.Lists;
50
51import java.io.FileNotFoundException;
52import java.util.ArrayList;
53import 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 */
60public 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