• 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.browse;
19 
20 import android.app.FragmentManager;
21 import android.content.ActivityNotFoundException;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.graphics.Bitmap;
25 import android.net.Uri;
26 import android.util.AttributeSet;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.View.OnClickListener;
30 import android.view.ViewGroup;
31 import android.view.ViewParent;
32 
33 import com.android.ex.photo.util.ImageUtils;
34 import com.android.mail.R;
35 import com.android.mail.analytics.Analytics;
36 import com.android.mail.photo.MailPhotoViewActivity;
37 import com.android.mail.providers.Attachment;
38 import com.android.mail.providers.UIProvider;
39 import com.android.mail.providers.UIProvider.AttachmentDestination;
40 import com.android.mail.providers.UIProvider.AttachmentRendition;
41 import com.android.mail.ui.AttachmentTile;
42 import com.android.mail.ui.AttachmentTileGrid;
43 import com.android.mail.utils.AttachmentUtils;
44 import com.android.mail.utils.LogTag;
45 import com.android.mail.utils.LogUtils;
46 import com.android.mail.utils.Utils;
47 
48 import java.util.Comparator;
49 import java.util.PriorityQueue;
50 
51 /**
52  * View for a single attachment in conversation view. Shows download status and allows launching
53  * intents to act on an attachment.
54  *
55  */
56 public class MessageAttachmentTile extends AttachmentTile implements OnClickListener,
57         AttachmentViewInterface {
58 
59     private int mPhotoIndex;
60     private Uri mAttachmentsListUri;
61     private View mTextContainer;
62 
63     private final AttachmentActionHandler mActionHandler;
64 
65     private static final String LOG_TAG = LogTag.getLogTag();
66 
MessageAttachmentTile(Context context)67     public MessageAttachmentTile(Context context) {
68         this(context, null);
69     }
70 
MessageAttachmentTile(Context context, AttributeSet attrs)71     public MessageAttachmentTile(Context context, AttributeSet attrs) {
72         super(context, attrs);
73 
74         mActionHandler = new AttachmentActionHandler(context, this);
75     }
76 
initialize(FragmentManager fragmentManager)77     public void initialize(FragmentManager fragmentManager) {
78         mActionHandler.initialize(fragmentManager);
79     }
80 
81     /**
82      * Render or update an attachment's view. This happens immediately upon instantiation, and
83      * repeatedly as status updates stream in, so only properties with new or changed values will
84      * cause sub-views to update.
85      */
86     @Override
render(Attachment attachment, Uri attachmentsListUri, int index, AttachmentPreviewCache attachmentPreviewCache, boolean loaderResult)87     public void render(Attachment attachment, Uri attachmentsListUri, int index,
88             AttachmentPreviewCache attachmentPreviewCache, boolean loaderResult) {
89         super.render(attachment, attachmentsListUri, index, attachmentPreviewCache, loaderResult);
90 
91         mAttachmentsListUri = attachmentsListUri;
92         mPhotoIndex = index;
93 
94         mActionHandler.setAttachment(mAttachment);
95         mActionHandler.updateStatus(loaderResult);
96     }
97 
inflate(LayoutInflater inflater, ViewGroup parent)98     public static MessageAttachmentTile inflate(LayoutInflater inflater, ViewGroup parent) {
99         MessageAttachmentTile view = (MessageAttachmentTile) inflater.inflate(
100                 R.layout.conversation_message_attachment_tile, parent, false);
101         return view;
102     }
103 
104 
105     @Override
onFinishInflate()106     protected void onFinishInflate() {
107         super.onFinishInflate();
108 
109         mTextContainer = findViewById(R.id.attachment_tile_text_container);
110 
111         setOnClickListener(this);
112     }
113 
114     @Override
onClick(View v)115     public void onClick(View v) {
116         onClick();
117     }
118 
onClick()119     private boolean onClick() {
120         showAndDownloadAttachments();
121         return true;
122     }
123 
showAndDownloadAttachments()124     private void showAndDownloadAttachments() {
125         AttachmentTileGrid tileGrid = ((AttachmentTileGrid) getParent());
126         int childCount = tileGrid.getChildCount();
127 
128         PriorityQueue<MessageAttachmentTile> queue = new PriorityQueue<MessageAttachmentTile>(
129                 childCount, new ViewIndexDistanceComparator(mPhotoIndex));
130         for (int i = 0; i < childCount; i++) {
131             MessageAttachmentTile tile = (MessageAttachmentTile) tileGrid.getChildAt(i);
132             queue.add(tile);
133         }
134 
135         // we want our downloads to have higher priority than the highest background downloads
136         int maxAdditionalPriority = childCount;
137         for (int i = 0; i < childCount; i++) {
138             // higher priority tiles are returned first
139             MessageAttachmentTile tile = queue.remove();
140             tile.downloadAttachment(maxAdditionalPriority - i, i != 0);
141         }
142 
143         viewAttachment();
144     }
145 
downloadAttachment(int additionalPriority, boolean delayDownload)146     public void downloadAttachment(int additionalPriority, boolean delayDownload) {
147         if (!mAttachment.isPresentLocally()) {
148             mActionHandler.startDownloadingAttachment(AttachmentDestination.CACHE,
149                     UIProvider.AttachmentRendition.BEST, additionalPriority, delayDownload);
150         }
151     }
152 
153     @Override
viewAttachment()154     public void viewAttachment() {
155         final String mime = Utils.normalizeMimeType(mAttachment.getContentType());
156 
157         Analytics.getInstance()
158                 .sendEvent("view_attachment", mime, "attachment_tile", mAttachment.size);
159 
160         if (ImageUtils.isImageMimeType(mime)) {
161             MailPhotoViewActivity
162                     .startMailPhotoViewActivity(getContext(), mAttachmentsListUri, mPhotoIndex);
163             return;
164         }
165 
166         Intent intent = new Intent(Intent.ACTION_VIEW);
167         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
168                 | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
169         Utils.setIntentDataAndTypeAndNormalize(
170                 intent, mAttachment.contentUri, mime);
171         try {
172             getContext().startActivity(intent);
173         } catch (ActivityNotFoundException e) {
174             // couldn't find activity for View intent
175             LogUtils.e(LOG_TAG, "Couldn't find Activity for intent", e);
176         }
177     }
178 
179     @Override
updateProgress(boolean showDeterminateProgress)180     public void updateProgress(boolean showDeterminateProgress) {
181         // do not show progress for image tiles
182     }
183 
184     @Override
onUpdateStatus()185     public void onUpdateStatus() {
186     }
187 
188     @Override
setThumbnailToDefault()189     public void setThumbnailToDefault() {
190         super.setThumbnailToDefault();
191         mTextContainer.setVisibility(VISIBLE);
192     }
193 
194     @Override
setThumbnail(Bitmap result)195     public void setThumbnail(Bitmap result) {
196         super.setThumbnail(result);
197         mTextContainer.setVisibility(GONE);
198     }
199 
200     @Override
thumbnailLoadFailed()201     public void thumbnailLoadFailed() {
202         super.thumbnailLoadFailed();
203 
204         if (AttachmentUtils.canDownloadAttachment(getContext(), null)) {
205             // Download if there is network. This check prevents the attachment
206             // download from failing and making the error toast show
207             mActionHandler.startDownloadingAttachment(
208                     AttachmentDestination.CACHE, AttachmentRendition.SIMPLE, 0, false);
209         }
210     }
211 
212     /**
213      * Given two child views, figure out whose index is closest to the specified
214      * index.
215      */
216     public static class ViewIndexDistanceComparator implements Comparator<View>{
217         final private int mIndex;
218         /**
219          * @param index Compare based on each view's distance to this index
220          */
ViewIndexDistanceComparator(int index)221         public ViewIndexDistanceComparator(int index) {
222             mIndex = index;
223         }
224 
225         @Override
compare(View lhs, View rhs)226         public int compare(View lhs, View rhs) {
227             ViewParent parent = lhs.getParent();
228             if (parent == rhs.getParent()) {
229                 if (parent instanceof ViewGroup) {
230                     ViewGroup p = (ViewGroup) parent;
231                     int lhsIndex = p.indexOfChild(lhs);
232                     int rhsIndex = p.indexOfChild(rhs);
233                     int lhsDistance = Math.abs(mIndex - lhsIndex);
234                     int rhsDistance = Math.abs(mIndex - rhsIndex);
235                     // prefer shorter distance since they are the next ones to be swiped to
236                     int result = lhsDistance - rhsDistance;
237                     if (result == 0) {
238                         // prefer higher index since they are to the right in the photoviewer
239                         return rhsIndex - lhsIndex;
240                     }
241                     return result;
242                 }
243             }
244             return 0;
245         }
246     }
247 }
248