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.analytics.Analytics;
36import com.android.mail.photo.MailPhotoViewActivity;
37import com.android.mail.providers.Attachment;
38import com.android.mail.providers.UIProvider;
39import com.android.mail.providers.UIProvider.AttachmentDestination;
40import com.android.mail.providers.UIProvider.AttachmentRendition;
41import com.android.mail.ui.AttachmentTile;
42import com.android.mail.ui.AttachmentTileGrid;
43import com.android.mail.utils.AttachmentUtils;
44import com.android.mail.utils.LogTag;
45import com.android.mail.utils.LogUtils;
46import com.android.mail.utils.Utils;
47
48import java.util.Comparator;
49import 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 */
56public 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
67    public MessageAttachmentTile(Context context) {
68        this(context, null);
69    }
70
71    public MessageAttachmentTile(Context context, AttributeSet attrs) {
72        super(context, attrs);
73
74        mActionHandler = new AttachmentActionHandler(context, this);
75    }
76
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
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
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
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
115    public void onClick(View v) {
116        onClick();
117    }
118
119    private boolean onClick() {
120        showAndDownloadAttachments();
121        return true;
122    }
123
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
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
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
180    public void updateProgress(boolean showDeterminateProgress) {
181        // do not show progress for image tiles
182    }
183
184    @Override
185    public void onUpdateStatus() {
186    }
187
188    @Override
189    public void setThumbnailToDefault() {
190        super.setThumbnailToDefault();
191        mTextContainer.setVisibility(VISIBLE);
192    }
193
194    @Override
195    public void setThumbnail(Bitmap result) {
196        super.setThumbnail(result);
197        mTextContainer.setVisibility(GONE);
198    }
199
200    @Override
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         */
221        public ViewIndexDistanceComparator(int index) {
222            mIndex = index;
223        }
224
225        @Override
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