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