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; 252fd167d6131482da984768b5ee75cefa32ed3e32Andrew Sappersteinimport android.support.v4.text.BidiFormatter; 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; 43e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huangimport com.android.mail.analytics.Analytics; 44f59d01c3116dc2adde97a5b52aa6094144c2d315Andrew Sappersteinimport com.android.mail.providers.Account; 454aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.providers.Attachment; 464aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.providers.UIProvider.AttachmentDestination; 474aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.providers.UIProvider.AttachmentState; 48f59d01c3116dc2adde97a5b52aa6094144c2d315Andrew Sappersteinimport com.android.mail.ui.AccountFeedbackActivity; 494aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.utils.AttachmentUtils; 50b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 514aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.utils.LogUtils; 524aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.utils.MimeType; 534aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sappersteinimport com.android.mail.utils.Utils; 544cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein 554aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein/** 564aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * View for a single attachment in conversation view. Shows download status and allows launching 574aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * intents to act on an attachment. 584aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * 594aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein */ 60e18f42d652e171cd4e4bb193482d2e131d91f26eMark Weipublic class MessageAttachmentBar extends FrameLayout implements OnClickListener, 614aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein OnMenuItemClickListener, AttachmentViewInterface { 624aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 634aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private Attachment mAttachment; 644aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private TextView mTitle; 654aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private TextView mSubTitle; 664aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private String mAttachmentSizeText; 674aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private String mDisplayType; 684aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private ProgressBar mProgress; 694c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein private ImageButton mCancelButton; 704aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private PopupMenu mPopup; 714aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private ImageView mOverflowButton; 724aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 734aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private final AttachmentActionHandler mActionHandler; 74c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein private boolean mSaveClicked; 75f59d01c3116dc2adde97a5b52aa6094144c2d315Andrew Sapperstein private Account mAccount; 764aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 7774313d9a9ea22d21658e805600f114a78a2fb935Mark Wei private final Runnable mUpdateRunnable = new Runnable() { 7874313d9a9ea22d21658e805600f114a78a2fb935Mark Wei @Override 7974313d9a9ea22d21658e805600f114a78a2fb935Mark Wei public void run() { 8074313d9a9ea22d21658e805600f114a78a2fb935Mark Wei updateActionsInternal(); 8174313d9a9ea22d21658e805600f114a78a2fb935Mark Wei } 8274313d9a9ea22d21658e805600f114a78a2fb935Mark Wei }; 8374313d9a9ea22d21658e805600f114a78a2fb935Mark Wei 84b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook private static final String LOG_TAG = LogTag.getLogTag(); 854aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 86833123d9c31b0b2dd23f7f74738c5bccf8a546d3Andrew Sapperstein /** 87833123d9c31b0b2dd23f7f74738c5bccf8a546d3Andrew Sapperstein * Boolean used to tell whether extra option 1 should always be hidden. 88833123d9c31b0b2dd23f7f74738c5bccf8a546d3Andrew Sapperstein * Currently makes sure that there is no conversation because that state 89833123d9c31b0b2dd23f7f74738c5bccf8a546d3Andrew Sapperstein * means that we're in the EML viewer. 90833123d9c31b0b2dd23f7f74738c5bccf8a546d3Andrew Sapperstein */ 91833123d9c31b0b2dd23f7f74738c5bccf8a546d3Andrew Sapperstein private boolean mHideExtraOptionOne; 92833123d9c31b0b2dd23f7f74738c5bccf8a546d3Andrew Sapperstein 937638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein 944aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein public MessageAttachmentBar(Context context) { 954aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein this(context, null); 964aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 974aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 984aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein public MessageAttachmentBar(Context context, AttributeSet attrs) { 994aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein super(context, attrs); 1004aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1014aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mActionHandler = new AttachmentActionHandler(context, this); 1024aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 1034aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1048081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook public void initialize(FragmentManager fragmentManager) { 1058081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook mActionHandler.initialize(fragmentManager); 1068081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook } 1078081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook 1084aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein public static MessageAttachmentBar inflate(LayoutInflater inflater, ViewGroup parent) { 1094aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein MessageAttachmentBar view = (MessageAttachmentBar) inflater.inflate( 1104aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein R.layout.conversation_message_attachment_bar, parent, false); 1114aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein return view; 1124aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 1134aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1144aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein /** 1154aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * Render or update an attachment's view. This happens immediately upon instantiation, and 1164aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * repeatedly as status updates stream in, so only properties with new or changed values will 1174aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * cause sub-views to update. 1184aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein */ 1194f347e811052f446c3958c76db278bcd7b39a44fAndy Huang public void render(Attachment attachment, Account account, ConversationMessage message, 1202fd167d6131482da984768b5ee75cefa32ed3e32Andrew Sapperstein boolean loaderResult, BidiFormatter bidiFormatter) { 1217638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein // get account uri for potential eml viewer usage 122f59d01c3116dc2adde97a5b52aa6094144c2d315Andrew Sapperstein mAccount = account; 1237638a1004e7c8ed7a85620243da3b051b60217e8Andrew Sapperstein 1244aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein final Attachment prevAttachment = mAttachment; 1254aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mAttachment = attachment; 126a2519e3a1444b8421261348279883108ad1d00beGreg Bullock if (mAccount != null) { 127a2519e3a1444b8421261348279883108ad1d00beGreg Bullock mActionHandler.setAccount(mAccount.getEmailAddress()); 128a2519e3a1444b8421261348279883108ad1d00beGreg Bullock } 1294f347e811052f446c3958c76db278bcd7b39a44fAndy Huang mActionHandler.setMessage(message); 1304aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mActionHandler.setAttachment(mAttachment); 131833123d9c31b0b2dd23f7f74738c5bccf8a546d3Andrew Sapperstein mHideExtraOptionOne = message.getConversation() == null; 1324aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 133c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein // reset mSaveClicked if we are not currently downloading 134c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein // So if the download fails or the download completes, we stop 135c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein // showing progress, etc 136c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein mSaveClicked = !attachment.isDownloading() ? false : mSaveClicked; 137c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein 1384aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein LogUtils.d(LOG_TAG, "got attachment list row: name=%s state/dest=%d/%d dled=%d" + 139519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon " contentUri=%s MIME=%s flags=%d", attachment.getName(), attachment.state, 1404aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein attachment.destination, attachment.downloadedSize, attachment.contentUri, 141519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon attachment.getContentType(), attachment.flags); 1424aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1437348cf23d9df1ea3c58674b2c67d8219a6094fcfAndrew Sapperstein final String attachmentName = attachment.getName(); 144519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon if ((attachment.flags & Attachment.FLAG_DUMMY_ATTACHMENT) != 0) { 145519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon mTitle.setText(R.string.load_attachment); 146519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon } else if (prevAttachment == null 1477348cf23d9df1ea3c58674b2c67d8219a6094fcfAndrew Sapperstein || !TextUtils.equals(attachmentName, prevAttachment.getName())) { 148f59d01c3116dc2adde97a5b52aa6094144c2d315Andrew Sapperstein mTitle.setText(attachmentName); 1494aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 1504aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1514aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein if (prevAttachment == null || attachment.size != prevAttachment.size) { 1522fd167d6131482da984768b5ee75cefa32ed3e32Andrew Sapperstein mAttachmentSizeText = bidiFormatter.unicodeWrap( 1532fd167d6131482da984768b5ee75cefa32ed3e32Andrew Sapperstein AttachmentUtils.convertToHumanReadableSize(getContext(), attachment.size)); 1542fd167d6131482da984768b5ee75cefa32ed3e32Andrew Sapperstein mDisplayType = bidiFormatter.unicodeWrap( 1552fd167d6131482da984768b5ee75cefa32ed3e32Andrew Sapperstein AttachmentUtils.getDisplayType(getContext(), attachment)); 156c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei updateSubtitleText(); 1574aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 1584aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1594aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein updateActions(); 1608081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook mActionHandler.updateStatus(loaderResult); 1614aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 1624aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1634aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein @Override 1644aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein protected void onFinishInflate() { 1654aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein super.onFinishInflate(); 1664aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1674aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mTitle = (TextView) findViewById(R.id.attachment_title); 1684aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mSubTitle = (TextView) findViewById(R.id.attachment_subtitle); 1694aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mProgress = (ProgressBar) findViewById(R.id.attachment_progress); 1704aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mOverflowButton = (ImageView) findViewById(R.id.overflow); 1714c7d8b5f38bfa80192d457025b834c975d7d38a3Andrew Sapperstein mCancelButton = (ImageButton) findViewById(R.id.cancel_attachment); 1724aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1734aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein setOnClickListener(this); 1744aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mOverflowButton.setOnClickListener(this); 1754aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mCancelButton.setOnClickListener(this); 1764aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 1774aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1784aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein @Override 1794aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein public void onClick(View v) { 1804aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein onClick(v.getId(), v); 1814aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 1824aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1834aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein @Override 1844aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein public boolean onMenuItemClick(MenuItem item) { 1854aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mPopup.dismiss(); 1864aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein return onClick(item.getItemId(), null); 1874aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 1884aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 1892b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy private boolean onClick(final int res, final View v) { 1902b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (res == R.id.preview_attachment) { 1912b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy previewAttachment(); 1922b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (res == R.id.save_attachment) { 1932b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mAttachment.canSave()) { 1942b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mActionHandler.startDownloadingAttachment(AttachmentDestination.EXTERNAL); 1952b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mSaveClicked = true; 196e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 197e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Analytics.getInstance().sendEvent( 198e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang "save_attachment", Utils.normalizeMimeType(mAttachment.getContentType()), 199e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang "attachment_bar", mAttachment.size); 2002b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 2012b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (res == R.id.download_again) { 2022b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mAttachment.isPresentLocally()) { 203ce9db80cf997f99b8c5d0ef8d22b074555aaf795Mark Wei mActionHandler.showDownloadingDialog(); 2042b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mActionHandler.startRedownloadingAttachment(mAttachment); 205e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 206e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Analytics.getInstance().sendEvent("redownload_attachment", 207e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Utils.normalizeMimeType(mAttachment.getContentType()), "attachment_bar", 208e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang mAttachment.size); 2092b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 2102b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (res == R.id.cancel_attachment) { 2112b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mActionHandler.cancelAttachment(); 2122b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mSaveClicked = false; 213e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 214e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Analytics.getInstance().sendEvent( 215e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang "cancel_attachment", Utils.normalizeMimeType(mAttachment.getContentType()), 216e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang "attachment_bar", mAttachment.size); 2174f347e811052f446c3958c76db278bcd7b39a44fAndy Huang } else if (res == R.id.attachment_extra_option1) { 2184f347e811052f446c3958c76db278bcd7b39a44fAndy Huang mActionHandler.handleOption1(); 2192b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (res == R.id.overflow) { 2202b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // If no overflow items are visible, just bail out. 2212b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // We shouldn't be able to get here anyhow since the overflow 2222b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // button should be hidden. 2232b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (shouldShowOverflow()) { 2244aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein if (mPopup == null) { 2254aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mPopup = new PopupMenu(getContext(), v); 2264aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mPopup.getMenuInflater().inflate(R.menu.message_footer_overflow_menu, 2274aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mPopup.getMenu()); 2284aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mPopup.setOnMenuItemClickListener(this); 2294aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 2304aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 2314aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein final Menu menu = mPopup.getMenu(); 232856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei menu.findItem(R.id.preview_attachment).setVisible(shouldShowPreview()); 233856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei menu.findItem(R.id.save_attachment).setVisible(shouldShowSave()); 234856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei menu.findItem(R.id.download_again).setVisible(shouldShowDownloadAgain()); 2354f347e811052f446c3958c76db278bcd7b39a44fAndy Huang menu.findItem(R.id.attachment_extra_option1).setVisible(shouldShowExtraOption1()); 2364aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 2374aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mPopup.show(); 2384aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 2392b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else { 2402b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Handles clicking the attachment 2412b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // in any area that is not the overflow 2422b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // button or cancel button or one of the 2432b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // overflow items. 244e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang final String mime = Utils.normalizeMimeType(mAttachment.getContentType()); 245e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang final String action; 246e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 247519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon if ((mAttachment.flags & Attachment.FLAG_DUMMY_ATTACHMENT) != 0) { 248519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon // This is a dummy. We need to download it, but not attempt to open or preview. 249519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon mActionHandler.showDownloadingDialog(); 250519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon mActionHandler.setViewOnFinish(false); 251519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon mActionHandler.startDownloadingAttachment(AttachmentDestination.CACHE); 252519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon 253519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon action = null; 254519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon } 2552b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // If we can install, install. 2562b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy else if (MimeType.isInstallable(mAttachment.getContentType())) { 2572b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Save to external because the package manager only handles 2582b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // file:// uris not content:// uris. We do the same 2592b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // workaround in 2602b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // UiProvider#getUiAttachmentsCursorForUIAttachments() 2612b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mActionHandler.showAttachment(AttachmentDestination.EXTERNAL); 262e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 263e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang action = "attachment_bar_install"; 2642b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 2652b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // If we can view or play with an on-device app, 2662b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // view or play. 2672b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy else if (MimeType.isViewable( 2682b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy getContext(), mAttachment.contentUri, mAttachment.getContentType())) { 2692b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy mActionHandler.showAttachment(AttachmentDestination.CACHE); 270e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 271e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang action = "attachment_bar"; 2722b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 2732b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // If we can only preview the attachment, preview. 2742b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy else if (mAttachment.canPreview()) { 2752b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy previewAttachment(); 276e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 277e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang action = null; 2782b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 2792b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy // Otherwise, if we cannot do anything, show the info dialog. 2802b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy else { 2812b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 2822b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy int dialogMessage = R.string.no_application_found; 2832b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy builder.setTitle(R.string.more_info_attachment) 2842b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy .setMessage(dialogMessage) 2852b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy .show(); 286e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 287e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang action = "attachment_bar_no_viewer"; 288e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang } 289e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 290e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang if (action != null) { 291e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Analytics.getInstance() 292e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang .sendEvent("view_attachment", mime, action, mAttachment.size); 2932b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } 2944aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 2954aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 2964aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein return true; 2974aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 2984aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 299856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei private boolean shouldShowPreview() { 300856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei // state could be anything 301856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei return mAttachment.canPreview(); 302856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei } 303856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei 304856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei private boolean shouldShowSave() { 305856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei return mAttachment.canSave() && !mSaveClicked; 306856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei } 307856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei 308856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei private boolean shouldShowDownloadAgain() { 309b5ef9a9497aeef6ccff95ce4f1e2e43912e3fcc4Mark Wei // implies state == SAVED || state == FAILED 3107434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein // and the attachment supports re-download 3117434e800d4313a227120ca36bd95683752a7879fAndrew Sapperstein return mAttachment.supportsDownloadAgain() && mAttachment.isDownloadFinishedOrFailed(); 312856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei } 313856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei 3144f347e811052f446c3958c76db278bcd7b39a44fAndy Huang private boolean shouldShowExtraOption1() { 315aa4c9941269cc7815dd80e649e24d0257f83d5d5Alex Gawley return !mHideExtraOptionOne && 316aa4c9941269cc7815dd80e649e24d0257f83d5d5Alex Gawley mActionHandler.shouldShowExtraOption1(mAttachment.getContentType()); 3174f347e811052f446c3958c76db278bcd7b39a44fAndy Huang } 3184f347e811052f446c3958c76db278bcd7b39a44fAndy Huang 319856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei private boolean shouldShowOverflow() { 320aa4c9941269cc7815dd80e649e24d0257f83d5d5Alex Gawley return (shouldShowPreview() || shouldShowSave() || shouldShowDownloadAgain() || 321aa4c9941269cc7815dd80e649e24d0257f83d5d5Alex Gawley shouldShowExtraOption1()) && !shouldShowCancel(); 322856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei } 323856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei 324856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei private boolean shouldShowCancel() { 325856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei return mAttachment.isDownloading() && mSaveClicked; 326856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei } 327856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei 328c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei @Override 3294aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein public void viewAttachment() { 330591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook if (mAttachment.contentUri == null) { 331591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook LogUtils.e(LOG_TAG, "viewAttachment with null content uri"); 332591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook return; 333591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook } 334591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook 3354aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein Intent intent = new Intent(Intent.ACTION_VIEW); 3364aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION 3374aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 3388d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein 3398d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein final String contentType = mAttachment.getContentType(); 340bf3a5c5aa46759a238b3ca197b97bc4182cba8b6Mark Wei Utils.setIntentDataAndTypeAndNormalize( 3418d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein intent, mAttachment.contentUri, contentType); 3428d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein 3438d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein // For EML files, we want to open our dedicated 3448d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein // viewer rather than let any activity open it. 3458d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein if (MimeType.isEmlMimeType(contentType)) { 3461b8d42f7d1711664a0bb0de0a8585ada6c24ffadRay Chen intent.setPackage(getContext().getPackageName()); 347f59d01c3116dc2adde97a5b52aa6094144c2d315Andrew Sapperstein intent.putExtra(AccountFeedbackActivity.EXTRA_ACCOUNT_URI, 348f59d01c3116dc2adde97a5b52aa6094144c2d315Andrew Sapperstein mAccount != null ? mAccount.uri : null); 3498d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein } 3508d4791ce70b3f71cc90256bc4b5b236379b56331Andrew Sapperstein 3514aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein try { 3524aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein getContext().startActivity(intent); 3534aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } catch (ActivityNotFoundException e) { 3544aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein // couldn't find activity for View intent 355591eb37fb6db41f014626d0df51e7dc055d07af0Paul Westbrook LogUtils.e(LOG_TAG, e, "Couldn't find Activity for intent"); 3564aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 3574aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 3584aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 3594aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private void previewAttachment() { 360d6318e56adadeff4106e9696b5330239175487b1Andrew Sapperstein if (mAttachment.canPreview()) { 361d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook final Intent previewIntent = 362d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook new Intent(Intent.ACTION_VIEW, mAttachment.previewIntentUri); 363d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook getContext().startActivity(previewIntent); 364e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang 365e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang Analytics.getInstance().sendEvent( 366e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang "preview_attachment", Utils.normalizeMimeType(mAttachment.getContentType()), 367e003b4cc4a23e6d394998bebe26430a361c5ac29Andy Huang null, mAttachment.size); 368d49db8e3c4fff459f4ae3869ea80d083461eda2cPaul Westbrook } 3694aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 3704aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 3713b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy private static void setButtonVisible(View button, boolean visible) { 3724aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein button.setVisibility(visible ? VISIBLE : GONE); 3734aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 3744aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 3754aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein /** 3764aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein * Update all actions based on current downloading state. 3774aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein */ 3784aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein private void updateActions() { 37974313d9a9ea22d21658e805600f114a78a2fb935Mark Wei removeCallbacks(mUpdateRunnable); 38074313d9a9ea22d21658e805600f114a78a2fb935Mark Wei post(mUpdateRunnable); 38174313d9a9ea22d21658e805600f114a78a2fb935Mark Wei } 38274313d9a9ea22d21658e805600f114a78a2fb935Mark Wei 38374313d9a9ea22d21658e805600f114a78a2fb935Mark Wei private void updateActionsInternal() { 384a95161cf364baeea1a9bb098b4f6db961ec8705bAndrew Sapperstein // If the progress dialog is visible, skip any of the updating 385bbe74aee04f669990e888095b0d6858dc1e17ce1Mark Wei if (mActionHandler.isProgressDialogVisible()) { 386a95161cf364baeea1a9bb098b4f6db961ec8705bAndrew Sapperstein return; 387a95161cf364baeea1a9bb098b4f6db961ec8705bAndrew Sapperstein } 388a95161cf364baeea1a9bb098b4f6db961ec8705bAndrew Sapperstein 3894aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein // To avoid visibility state transition bugs, every button's visibility should be touched 3904aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein // once by this routine. 391856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei setButtonVisible(mCancelButton, shouldShowCancel()); 392856200a2abc6a90711f6eb99fc0340dd75ef6e9bMark Wei setButtonVisible(mOverflowButton, shouldShowOverflow()); 3934aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 3944aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 395c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei @Override 396532f48253d23ffcb974ab61856df131021dde02aAndrew Sapperstein public void onUpdateStatus() { 397c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei updateSubtitleText(); 3984aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 3994aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 400c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei @Override 4014aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein public void updateProgress(boolean showProgress) { 4024dabcc9f74ea5f75467f6f581d8ef7cd65c2f06ePaul Westbrook if (mAttachment.isDownloading()) { 403c445aba31c5cc6add9d51296b2c6f5cf89a1e584Andrew Sapperstein mProgress.setMax(mAttachment.size); 4044aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mProgress.setProgress(mAttachment.downloadedSize); 4054aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mProgress.setIndeterminate(!showProgress); 4064aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mProgress.setVisibility(VISIBLE); 407e18f42d652e171cd4e4bb193482d2e131d91f26eMark Wei mSubTitle.setVisibility(INVISIBLE); 4084aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } else { 4094aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mProgress.setVisibility(INVISIBLE); 410e18f42d652e171cd4e4bb193482d2e131d91f26eMark Wei mSubTitle.setVisibility(VISIBLE); 4114aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 4124aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 4134aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein 414c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei private void updateSubtitleText() { 4154aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein // TODO: make this a formatted resource when we have a UX design. 4164aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein // not worth translation right now. 417c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei final StringBuilder sb = new StringBuilder(); 418c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei if (mAttachment.state == AttachmentState.FAILED) { 419c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei sb.append(getResources().getString(R.string.download_failed)); 420c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei } else { 421c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei if (mAttachment.isSavedToExternal()) { 422c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei sb.append(getResources().getString(R.string.saved, mAttachmentSizeText)); 423c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei } else { 424c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei sb.append(mAttachmentSizeText); 425c40e5e818876db551e8f7c6f506ebaf38f73ac7aMark Wei } 426519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon if (mDisplayType != null) { 427519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon sb.append(' '); 428519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon sb.append(mDisplayType); 429519c218db6109003ca72a35ffe276ed69b0230a4Martin Hibdon } 4304aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 4314aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein mSubTitle.setText(sb.toString()); 4324aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein } 4334aa1c1340556c646175c3d0b193be05876ad95a0Andrew Sapperstein} 434