MessageAttachmentBar.java revision ce9db80cf997f99b8c5d0ef8d22b074555aaf795
14aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein/*
24aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * Copyright (C) 2012 Google Inc.
34aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * Licensed to The Android Open Source Project.
44aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein *
54aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License");
64aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * you may not use this file except in compliance with the License.
74aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * You may obtain a copy of the License at
84aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein *
94aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein *      http://www.apache.org/licenses/LICENSE-2.0
104aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein *
114aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * Unless required by applicable law or agreed to in writing, software
124aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS,
134aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * See the License for the specific language governing permissions and
154aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * limitations under the License.
164aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein */
174aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
184aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinpackage com.android.mail.browse;
194aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
204aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.app.AlertDialog;
218081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrookimport android.app.FragmentManager;
224aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.content.ActivityNotFoundException;
234aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.content.Context;
244aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.content.Intent;
257638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sappersteinimport android.net.Uri;
264aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.text.TextUtils;
274aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.util.AttributeSet;
284aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.view.LayoutInflater;
294aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.view.Menu;
304aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.view.MenuItem;
314aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.view.View;
324aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.view.View.OnClickListener;
334aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.view.ViewGroup;
34e18f42d652e171cd4e4bb193482d2e131d91f26eMark Weiimport android.widget.FrameLayout;
354c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sappersteinimport android.widget.ImageButton;
364aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.widget.ImageView;
374aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.widget.PopupMenu;
384aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.widget.PopupMenu.OnMenuItemClickListener;
394aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.widget.ProgressBar;
404aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport android.widget.TextView;
414aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
424aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.R;
434aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.providers.Attachment;
444aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.providers.UIProvider.AttachmentDestination;
454aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.providers.UIProvider.AttachmentState;
464aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.utils.AttachmentUtils;
47b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
484aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.utils.LogUtils;
494aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.utils.MimeType;
504aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.utils.Utils;
514cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein
524aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein/**
534aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * View for a single attachment in conversation view. Shows download status and allows launching
544aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * intents to act on an attachment.
554aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein *
564aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein */
57e18f42d652e171cd4e4bb193482d2e131d91f26eMark Weipublic class MessageAttachmentBar extends FrameLayout implements OnClickListener,
584aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        OnMenuItemClickListener, AttachmentViewInterface {
594aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
604aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private Attachment mAttachment;
614aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private TextView mTitle;
624aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private TextView mSubTitle;
634aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private String mAttachmentSizeText;
644aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private String mDisplayType;
654aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private ProgressBar mProgress;
664c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein    private ImageButton mCancelButton;
674aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private PopupMenu mPopup;
684aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private ImageView mOverflowButton;
694aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
704aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private final AttachmentActionHandler mActionHandler;
71c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein    private boolean mSaveClicked;
727638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein    private Uri mAccountUri;
734aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
7474313d9a9ea22d21658e805600f114a78a2fb935Mark Wei    private final Runnable mUpdateRunnable = new Runnable() {
7574313d9a9ea22d21658e805600f114a78a2fb935Mark Wei            @Override
7674313d9a9ea22d21658e805600f114a78a2fb935Mark Wei        public void run() {
7774313d9a9ea22d21658e805600f114a78a2fb935Mark Wei            updateActionsInternal();
7874313d9a9ea22d21658e805600f114a78a2fb935Mark Wei        }
7974313d9a9ea22d21658e805600f114a78a2fb935Mark Wei    };
8074313d9a9ea22d21658e805600f114a78a2fb935Mark Wei
81b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
824aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
837638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein
844aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    public MessageAttachmentBar(Context context) {
854aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        this(context, null);
864aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
874aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
884aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    public MessageAttachmentBar(Context context, AttributeSet attrs) {
894aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        super(context, attrs);
904aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
914aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mActionHandler = new AttachmentActionHandler(context, this);
924aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
934aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
948081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook    public void initialize(FragmentManager fragmentManager) {
958081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        mActionHandler.initialize(fragmentManager);
968081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook    }
978081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook
984aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    public static MessageAttachmentBar inflate(LayoutInflater inflater, ViewGroup parent) {
994aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        MessageAttachmentBar view = (MessageAttachmentBar) inflater.inflate(
1004aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                R.layout.conversation_message_attachment_bar, parent, false);
1014aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        return view;
1024aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
1034aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1044aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    /**
1054aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein     * Render or update an attachment's view. This happens immediately upon instantiation, and
1064aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein     * repeatedly as status updates stream in, so only properties with new or changed values will
1074aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein     * cause sub-views to update.
1084aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein     */
1097638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein    public void render(Attachment attachment, Uri accountUri, boolean loaderResult) {
1107638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein        // get account uri for potential eml viewer usage
1117638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein        mAccountUri = accountUri;
1127638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein
1134aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        final Attachment prevAttachment = mAttachment;
1144aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mAttachment = attachment;
1154aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mActionHandler.setAttachment(mAttachment);
1164aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
117c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein        // reset mSaveClicked if we are not currently downloading
118c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein        // So if the download fails or the download completes, we stop
119c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein        // showing progress, etc
120c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein        mSaveClicked = !attachment.isDownloading() ? false : mSaveClicked;
121c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein
1224aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        LogUtils.d(LOG_TAG, "got attachment list row: name=%s state/dest=%d/%d dled=%d" +
1238750066b10f80e2a8080016973b3296d76d18266Mark Wei                " contentUri=%s MIME=%s", attachment.getName(), attachment.state,
1244aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                attachment.destination, attachment.downloadedSize, attachment.contentUri,
1258750066b10f80e2a8080016973b3296d76d18266Mark Wei                attachment.getContentType());
1264aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
127381c6b390dfbfdf7040dcc2193438c70c6f66b9fMark Wei        if (prevAttachment == null
128381c6b390dfbfdf7040dcc2193438c70c6f66b9fMark Wei                || !TextUtils.equals(attachment.getName(), prevAttachment.getName())) {
1298750066b10f80e2a8080016973b3296d76d18266Mark Wei            mTitle.setText(attachment.getName());
1304aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        }
1314aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1324aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        if (prevAttachment == null || attachment.size != prevAttachment.size) {
1334aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein            mAttachmentSizeText = AttachmentUtils.convertToHumanReadableSize(getContext(),
1344aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                    attachment.size);
1354aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein            mDisplayType = AttachmentUtils.getDisplayType(getContext(), attachment);
136c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei            updateSubtitleText();
1374aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        }
1384aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1394aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        updateActions();
1408081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        mActionHandler.updateStatus(loaderResult);
1414aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
1424aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1434aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    @Override
1444aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    protected void onFinishInflate() {
1454aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        super.onFinishInflate();
1464aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1474aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mTitle = (TextView) findViewById(R.id.attachment_title);
1484aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mSubTitle = (TextView) findViewById(R.id.attachment_subtitle);
1494aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mProgress = (ProgressBar) findViewById(R.id.attachment_progress);
1504aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mOverflowButton = (ImageView) findViewById(R.id.overflow);
1514c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein        mCancelButton = (ImageButton) findViewById(R.id.cancel_attachment);
1524aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1534aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        setOnClickListener(this);
1544aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mOverflowButton.setOnClickListener(this);
1554aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mCancelButton.setOnClickListener(this);
1564aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
1574aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1584aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    @Override
1594aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    public void onClick(View v) {
1604aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        onClick(v.getId(), v);
1614aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
1624aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1634aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    @Override
1644aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    public boolean onMenuItemClick(MenuItem item) {
1654aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mPopup.dismiss();
1664aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        return onClick(item.getItemId(), null);
1674aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
1684aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1692b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy    private boolean onClick(final int res, final View v) {
1702b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        if (res == R.id.preview_attachment) {
1712b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            previewAttachment();
1722b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (res == R.id.save_attachment) {
1732b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            if (mAttachment.canSave()) {
1742b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                mActionHandler.startDownloadingAttachment(AttachmentDestination.EXTERNAL);
1752b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                mSaveClicked = true;
1762b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            }
1772b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (res == R.id.download_again) {
1782b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            if (mAttachment.isPresentLocally()) {
179ce9db80cf997f99b8c5d0ef8d22b074555aaf795Mark Wei                mActionHandler.showDownloadingDialog();
1802b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                mActionHandler.startRedownloadingAttachment(mAttachment);
1812b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            }
1822b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (res == R.id.cancel_attachment) {
1832b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            mActionHandler.cancelAttachment();
1842b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            mSaveClicked = false;
1852b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (res == R.id.overflow) {
1862b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // If no overflow items are visible, just bail out.
1872b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // We shouldn't be able to get here anyhow since the overflow
1882b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // button should be hidden.
1892b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            if (shouldShowOverflow()) {
1904aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                if (mPopup == null) {
1914aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                    mPopup = new PopupMenu(getContext(), v);
1924aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                    mPopup.getMenuInflater().inflate(R.menu.message_footer_overflow_menu,
1934aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                            mPopup.getMenu());
1944aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                    mPopup.setOnMenuItemClickListener(this);
1954aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                }
1964aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
1974aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                final Menu menu = mPopup.getMenu();
198856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei                menu.findItem(R.id.preview_attachment).setVisible(shouldShowPreview());
199856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei                menu.findItem(R.id.save_attachment).setVisible(shouldShowSave());
200856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei                menu.findItem(R.id.download_again).setVisible(shouldShowDownloadAgain());
2014aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
2024aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                mPopup.show();
2034aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein            }
2042b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else {
2052b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // Handles clicking the attachment
2062b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // in any area that is not the overflow
2072b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // button or cancel button or one of the
2082b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // overflow items.
2092b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy
2102b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // If the mimetype is blocked, show the info dialog
2112b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            if (MimeType.isBlocked(mAttachment.getContentType())) {
2122b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
2132b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                int dialogMessage = R.string.attachment_type_blocked;
2142b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                builder.setTitle(R.string.more_info_attachment)
2152b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                       .setMessage(dialogMessage)
2162b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                       .show();
2172b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            }
2182b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // If we can install, install.
2192b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            else if (MimeType.isInstallable(mAttachment.getContentType())) {
2202b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                // Save to external because the package manager only handles
2212b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                // file:// uris not content:// uris. We do the same
2222b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                // workaround in
2232b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                // UiProvider#getUiAttachmentsCursorForUIAttachments()
2242b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                mActionHandler.showAttachment(AttachmentDestination.EXTERNAL);
2252b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            }
2262b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // If we can view or play with an on-device app,
2272b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // view or play.
2282b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            else if (MimeType.isViewable(
2292b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                    getContext(), mAttachment.contentUri, mAttachment.getContentType())) {
2302b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                mActionHandler.showAttachment(AttachmentDestination.CACHE);
2312b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            }
2322b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // If we can only preview the attachment, preview.
2332b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            else if (mAttachment.canPreview()) {
2342b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                previewAttachment();
2352b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            }
2362b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            // Otherwise, if we cannot do anything, show the info dialog.
2372b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            else {
2382b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
2392b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                int dialogMessage = R.string.no_application_found;
2402b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                builder.setTitle(R.string.more_info_attachment)
2412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                       .setMessage(dialogMessage)
2422b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                       .show();
2432b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            }
2444aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        }
2454aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
2464aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        return true;
2474aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
2484aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
249856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    private boolean shouldShowPreview() {
250856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei        // state could be anything
251856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei        return mAttachment.canPreview();
252856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    }
253856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei
254856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    private boolean shouldShowSave() {
255856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei        return mAttachment.canSave() && !mSaveClicked;
256856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    }
257856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei
258856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    private boolean shouldShowDownloadAgain() {
259b5ef9a9497aeef6ccff95ce4f1e2e43912e3fcc4Mark Wei        // implies state == SAVED || state == FAILED
2607434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        // and the attachment supports re-download
2617434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein        return mAttachment.supportsDownloadAgain() && mAttachment.isDownloadFinishedOrFailed();
262856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    }
263856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei
264856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    private boolean shouldShowOverflow() {
265856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei        return (shouldShowPreview() || shouldShowSave() || shouldShowDownloadAgain())
266856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei                && !shouldShowCancel();
267856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    }
268856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei
269856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    private boolean shouldShowCancel() {
270856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei        return mAttachment.isDownloading() && mSaveClicked;
271856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei    }
272856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei
273c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei    @Override
2744aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    public void viewAttachment() {
275591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook        if (mAttachment.contentUri == null) {
276591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook            LogUtils.e(LOG_TAG, "viewAttachment with null content uri");
277591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook            return;
278591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook        }
279591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook
2804aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        Intent intent = new Intent(Intent.ACTION_VIEW);
2814aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
2824aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein                | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
2838d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein
2848d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein        final String contentType = mAttachment.getContentType();
285bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei        Utils.setIntentDataAndTypeAndNormalize(
2868d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein                intent, mAttachment.contentUri, contentType);
2878d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein
2888d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein        // For EML files, we want to open our dedicated
2898d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein        // viewer rather than let any activity open it.
2908d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein        if (MimeType.isEmlMimeType(contentType)) {
2918d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein            intent.setClass(getContext(), EmlViewerActivity.class);
2927638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein            intent.putExtra(EmlViewerActivity.EXTRA_ACCOUNT_URI, mAccountUri);
2938d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein        }
2948d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein
2954aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        try {
2964aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein            getContext().startActivity(intent);
2974aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        } catch (ActivityNotFoundException e) {
2984aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein            // couldn't find activity for View intent
299591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook            LogUtils.e(LOG_TAG, e, "Couldn't find Activity for intent");
3004aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        }
3014aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
3024aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
3034aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private void previewAttachment() {
304d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein        if (mAttachment.canPreview()) {
305d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook            final Intent previewIntent =
306d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook                    new Intent(Intent.ACTION_VIEW, mAttachment.previewIntentUri);
307d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook            getContext().startActivity(previewIntent);
308d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook        }
3094aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
3104aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
3113b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy    private static void setButtonVisible(View button, boolean visible) {
3124aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        button.setVisibility(visible ? VISIBLE : GONE);
3134aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
3144aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
3154aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    /**
3164aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein     * Update all actions based on current downloading state.
3174aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein     */
3184aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    private void updateActions() {
31974313d9a9ea22d21658e805600f114a78a2fb935Mark Wei        removeCallbacks(mUpdateRunnable);
32074313d9a9ea22d21658e805600f114a78a2fb935Mark Wei        post(mUpdateRunnable);
32174313d9a9ea22d21658e805600f114a78a2fb935Mark Wei    }
32274313d9a9ea22d21658e805600f114a78a2fb935Mark Wei
32374313d9a9ea22d21658e805600f114a78a2fb935Mark Wei    private void updateActionsInternal() {
324a95161cf364baeea1a9bb098b4f6db961ec8705bAndrew Sapperstein        // If the progress dialog is visible, skip any of the updating
325bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei        if (mActionHandler.isProgressDialogVisible()) {
326a95161cf364baeea1a9bb098b4f6db961ec8705bAndrew Sapperstein            return;
327a95161cf364baeea1a9bb098b4f6db961ec8705bAndrew Sapperstein        }
328a95161cf364baeea1a9bb098b4f6db961ec8705bAndrew Sapperstein
3294aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        // To avoid visibility state transition bugs, every button's visibility should be touched
3304aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        // once by this routine.
331856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei        setButtonVisible(mCancelButton, shouldShowCancel());
332856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei        setButtonVisible(mOverflowButton, shouldShowOverflow());
3334aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
3344aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
335c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei    @Override
336532f48253d23ffcb974ab61856df131021dde02aAndrew Sapperstein    public void onUpdateStatus() {
337c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei        updateSubtitleText();
3384aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
3394aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
340c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei    @Override
3414aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    public void updateProgress(boolean showProgress) {
3424dabcc9f74ea5f75467f6f581d8ef7cd65c2f06ePaul Westbrook        if (mAttachment.isDownloading()) {
343c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein            mProgress.setMax(mAttachment.size);
3444aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein            mProgress.setProgress(mAttachment.downloadedSize);
3454aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein            mProgress.setIndeterminate(!showProgress);
3464aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein            mProgress.setVisibility(VISIBLE);
347e18f42d652e171cd4e4bb193482d2e131d91f26eMark Wei            mSubTitle.setVisibility(INVISIBLE);
3484aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        } else {
3494aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein            mProgress.setVisibility(INVISIBLE);
350e18f42d652e171cd4e4bb193482d2e131d91f26eMark Wei            mSubTitle.setVisibility(VISIBLE);
3514aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        }
3524aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
3534aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein
354c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei    private void updateSubtitleText() {
3554aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        // TODO: make this a formatted resource when we have a UX design.
3564aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        // not worth translation right now.
357c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei        final StringBuilder sb = new StringBuilder();
358c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei        if (mAttachment.state == AttachmentState.FAILED) {
359c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei            sb.append(getResources().getString(R.string.download_failed));
360c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei        } else {
361c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei            if (mAttachment.isSavedToExternal()) {
362c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei                sb.append(getResources().getString(R.string.saved, mAttachmentSizeText));
363c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei            } else {
364c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei                sb.append(mAttachmentSizeText);
365c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei            }
366c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei            sb.append(' ');
367c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei            sb.append(mDisplayType);
3684aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        }
3694aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein        mSubTitle.setText(sb.toString());
3704aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein    }
3714aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein}
372