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