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