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