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
20
21import android.app.DialogFragment;
22import android.app.Fragment;
23import android.app.FragmentManager;
24import android.app.FragmentTransaction;
25import android.content.ActivityNotFoundException;
26import android.content.ContentValues;
27import android.content.Context;
28import android.content.Intent;
29import android.net.Uri;
30import android.os.Handler;
31import android.os.Parcelable;
32
33import com.android.mail.providers.Attachment;
34import com.android.mail.providers.UIProvider;
35import com.android.mail.providers.UIProvider.AttachmentColumns;
36import com.android.mail.providers.UIProvider.AttachmentContentValueKeys;
37import com.android.mail.providers.UIProvider.AttachmentDestination;
38import com.android.mail.providers.UIProvider.AttachmentState;
39import com.android.mail.utils.LogTag;
40import com.android.mail.utils.LogUtils;
41import com.android.mail.utils.Utils;
42
43import java.util.ArrayList;
44
45public class AttachmentActionHandler {
46    private static final String PROGRESS_FRAGMENT_TAG = "attachment-progress";
47
48    private Attachment mAttachment;
49
50    private final AttachmentCommandHandler mCommandHandler;
51    private final AttachmentViewInterface mView;
52    private final Context mContext;
53    private final Handler mHandler;
54    private FragmentManager mFragmentManager;
55    private boolean mViewOnFinish;
56
57    private static final String LOG_TAG = LogTag.getLogTag();
58
59    public AttachmentActionHandler(Context context, AttachmentViewInterface view) {
60        mCommandHandler = new AttachmentCommandHandler(context);
61        mView = view;
62        mContext = context;
63        mHandler = new Handler();
64        mViewOnFinish = true;
65    }
66
67    public void initialize(FragmentManager fragmentManager) {
68        mFragmentManager = fragmentManager;
69    }
70
71    public void setAttachment(Attachment attachment) {
72        mAttachment = attachment;
73    }
74
75    public void setViewOnFinish(boolean viewOnFinish) {
76        mViewOnFinish = viewOnFinish;
77    }
78
79    public void showAttachment(int destination) {
80        if (mView == null) {
81            return;
82        }
83
84        // If the caller requested that this attachments be saved to the external storage, we should
85        // verify that the it was saved there.
86        if (mAttachment.isPresentLocally() &&
87                (destination == AttachmentDestination.CACHE ||
88                        mAttachment.destination == destination)) {
89            mView.viewAttachment();
90        } else {
91            showDownloadingDialog();
92            startDownloadingAttachment(destination);
93        }
94    }
95
96    /**
97     * Start downloading the full size attachment set with
98     * {@link #setAttachment(Attachment)} immediately.
99     */
100    public void startDownloadingAttachment(int destination) {
101        startDownloadingAttachment(destination, UIProvider.AttachmentRendition.BEST, 0, false);
102    }
103
104    public void startDownloadingAttachment(
105            int destination, int rendition, int additionalPriority, boolean delayDownload) {
106        startDownloadingAttachment(
107                mAttachment, destination, rendition, additionalPriority, delayDownload);
108    }
109
110    private void startDownloadingAttachment(
111            Attachment attachment, int destination, int rendition, int additionalPriority,
112            boolean delayDownload) {
113        final ContentValues params = new ContentValues(5);
114        params.put(AttachmentColumns.STATE, AttachmentState.DOWNLOADING);
115        params.put(AttachmentColumns.DESTINATION, destination);
116        params.put(AttachmentContentValueKeys.RENDITION, rendition);
117        params.put(AttachmentContentValueKeys.ADDITIONAL_PRIORITY, additionalPriority);
118        params.put(AttachmentContentValueKeys.DELAY_DOWNLOAD, delayDownload);
119
120        mCommandHandler.sendCommand(attachment.uri, params);
121    }
122
123    public void cancelAttachment() {
124        final ContentValues params = new ContentValues(1);
125        params.put(AttachmentColumns.STATE, AttachmentState.NOT_SAVED);
126
127        mCommandHandler.sendCommand(mAttachment.uri, params);
128    }
129
130    public void startRedownloadingAttachment(Attachment attachment) {
131        final ContentValues params = new ContentValues(2);
132        params.put(AttachmentColumns.STATE, AttachmentState.REDOWNLOADING);
133        params.put(AttachmentColumns.DESTINATION, attachment.destination);
134
135        mCommandHandler.sendCommand(attachment.uri, params);
136    }
137
138    /**
139     * Displays a loading dialog to be used for downloading attachments.
140     * Must be called on the UI thread.
141     */
142    public void showDownloadingDialog() {
143        final FragmentTransaction ft = mFragmentManager.beginTransaction();
144        final Fragment prev = mFragmentManager.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
145        if (prev != null) {
146            ft.remove(prev);
147        }
148        ft.addToBackStack(null);
149
150         // Create and show the dialog.
151        final DialogFragment newFragment = AttachmentProgressDialogFragment.newInstance(
152                mAttachment);
153        newFragment.show(ft, PROGRESS_FRAGMENT_TAG);
154    }
155
156    /**
157     * Update progress-related views. Will also trigger a view intent if a progress dialog was
158     * previously brought up (by tapping 'View') and the download has now finished.
159     */
160    public void updateStatus(boolean loaderResult) {
161        if (mView == null) {
162            return;
163        }
164
165        final boolean showProgress = mAttachment.shouldShowProgress();
166
167        final AttachmentProgressDialogFragment dialog = (AttachmentProgressDialogFragment)
168                mFragmentManager.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
169        if (dialog != null && dialog.isShowingDialogForAttachment(mAttachment)) {
170            dialog.setProgress(mAttachment.downloadedSize);
171
172            // We don't want the progress bar to switch back to indeterminate mode after
173            // have been in determinate progress mode.
174            final boolean indeterminate = !showProgress && dialog.isIndeterminate();
175            dialog.setIndeterminate(indeterminate);
176
177            if (loaderResult && mAttachment.isDownloadFinishedOrFailed()) {
178                mHandler.post(new Runnable() {
179                    @Override
180                    public void run() {
181                        dialog.dismiss();
182                    }
183                });
184            }
185
186            if (mAttachment.state == AttachmentState.SAVED && mViewOnFinish) {
187                mView.viewAttachment();
188            }
189        } else {
190            mView.updateProgress(showProgress);
191        }
192
193        // Call on update status for the view so that it can do some specific things.
194        mView.onUpdateStatus();
195    }
196
197    public boolean isProgressDialogVisible() {
198        final Fragment dialog = mFragmentManager.findFragmentByTag(PROGRESS_FRAGMENT_TAG);
199        return dialog != null && dialog.isVisible();
200    }
201
202    public void shareAttachment() {
203        if (mAttachment.contentUri == null) {
204            return;
205        }
206
207        Intent intent = new Intent(Intent.ACTION_SEND);
208        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
209                | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
210
211        final Uri uri = Utils.normalizeUri(mAttachment.contentUri);
212        intent.putExtra(Intent.EXTRA_STREAM, uri);
213        intent.setType(Utils.normalizeMimeType(mAttachment.getContentType()));
214
215        try {
216            mContext.startActivity(intent);
217        } catch (ActivityNotFoundException e) {
218            // couldn't find activity for SEND intent
219            LogUtils.e(LOG_TAG, "Couldn't find Activity for intent", e);
220        }
221    }
222
223    public void shareAttachments(ArrayList<Parcelable> uris) {
224        Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
225        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
226                | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
227
228        intent.setType("image/*");
229        intent.putParcelableArrayListExtra(
230                Intent.EXTRA_STREAM, uris);
231
232        try {
233            mContext.startActivity(intent);
234        } catch (ActivityNotFoundException e) {
235            // couldn't find activity for SEND_MULTIPLE intent
236            LogUtils.e(LOG_TAG, "Couldn't find Activity for intent", e);
237        }
238    }
239}
240