1bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook/* 2bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Copyright (C) 2010 The Android Open Source Project 3bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 4bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Licensed under the Apache License, Version 2.0 (the "License"); 5bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * you may not use this file except in compliance with the License. 6bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * You may obtain a copy of the License at 7bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 8bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * http://www.apache.org/licenses/LICENSE-2.0 9bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 10bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Unless required by applicable law or agreed to in writing, software 11bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * distributed under the License is distributed on an "AS IS" BASIS, 12bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * See the License for the specific language governing permissions and 14bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * limitations under the License. 15bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 16bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 17bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookpackage com.android.email.activity; 18bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 19bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.app.Activity; 20bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.app.DownloadManager; 21bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.app.Fragment; 22bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.app.LoaderManager.LoaderCallbacks; 23bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.ActivityNotFoundException; 24bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.ContentResolver; 25bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.ContentUris; 26bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.Context; 27bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.Intent; 28bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.Loader; 29bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.pm.PackageManager; 30bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.res.Resources; 31bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.database.ContentObserver; 32bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.graphics.Bitmap; 33bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.graphics.BitmapFactory; 34bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.media.MediaScannerConnection; 35bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.net.Uri; 36bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.os.Bundle; 37bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.os.Environment; 38bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.os.Handler; 39bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.provider.ContactsContract; 40bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.provider.ContactsContract.QuickContact; 41bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.text.SpannableStringBuilder; 42bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.text.TextUtils; 43bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.text.format.DateUtils; 44bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.util.Log; 45bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.util.Patterns; 46bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.LayoutInflater; 47bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.View; 48bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.ViewGroup; 49bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.webkit.WebSettings; 50bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.webkit.WebView; 51bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.webkit.WebViewClient; 52bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.Button; 53bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.ImageView; 54bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.LinearLayout; 55bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.ProgressBar; 56bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.TextView; 57bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 58bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.AttachmentInfo; 59bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.Controller; 60bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.ControllerResultUiThreadWrapper; 61bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.Email; 62bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.Preferences; 63bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.R; 64bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.Throttle; 65bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.mail.internet.EmailHtmlUtil; 66bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.service.AttachmentDownloadService; 67bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.Logging; 68bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.mail.Address; 69bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.mail.MessagingException; 70bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.provider.Account; 71bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.provider.EmailContent.Attachment; 72bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.provider.EmailContent.Body; 73bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.provider.EmailContent.Message; 74bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.provider.Mailbox; 75bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.utility.AttachmentUtilities; 76bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.utility.EmailAsyncTask; 77bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.utility.Utility; 78bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.google.common.collect.Maps; 79bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 80bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport org.apache.commons.io.IOUtils; 81bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 82bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.io.File; 83bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.io.FileOutputStream; 84bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.io.IOException; 85bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.io.InputStream; 86bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.io.OutputStream; 87bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.util.Formatter; 88bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.util.Map; 89bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.util.regex.Matcher; 90bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.util.regex.Pattern; 91bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 92bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook// TODO Better handling of config changes. 93bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook// - Retain the content; don't kick 3 async tasks every time 94bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 95bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook/** 96bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Base class for {@link MessageViewFragment} and {@link MessageFileViewFragment}. 97bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 98bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookpublic abstract class MessageViewFragmentBase extends Fragment implements View.OnClickListener { 99bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final String BUNDLE_KEY_CURRENT_TAB = "MessageViewFragmentBase.currentTab"; 100bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final String BUNDLE_KEY_PICTURE_LOADED = "MessageViewFragmentBase.pictureLoaded"; 101bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final int PHOTO_LOADER_ID = 1; 102bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected Context mContext; 103bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 104bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Regex that matches start of img tag. '<(?i)img\s+'. 105bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final Pattern IMG_TAG_START_REGEX = Pattern.compile("<(?i)img\\s+"); 106bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Regex that matches Web URL protocol part as case insensitive. 107bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final Pattern WEB_URL_PROTOCOL = Pattern.compile("(?i)http|https://"); 108bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 109bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static int PREVIEW_ICON_WIDTH = 62; 110bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static int PREVIEW_ICON_HEIGHT = 62; 111bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 112bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // The different levels of zoom: read from the Preferences. 113bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static String[] sZoomSizes = null; 114bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 115bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mSubjectView; 116bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mFromNameView; 117bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mFromAddressView; 118bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mDateTimeView; 119bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mAddressesView; 120bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private WebView mMessageContentView; 121bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private LinearLayout mAttachments; 122bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mTabSection; 123bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private ImageView mFromBadge; 124bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private ImageView mSenderPresenceView; 125bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mMainView; 126bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mLoadingProgress; 127bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mDetailsCollapsed; 128bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mDetailsExpanded; 129bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mDetailsFilled; 130bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 131bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mMessageTab; 132bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mAttachmentTab; 133bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mInviteTab; 134bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // It is not really a tab, but looks like one of them. 135bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mShowPicturesTab; 136bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mAlwaysShowPicturesButton; 137bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 138bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mAttachmentsScroll; 139bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mInviteScroll; 140bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 141bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private long mAccountId = Account.NO_ACCOUNT; 142bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private long mMessageId = Message.NO_MESSAGE; 143bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Message mMessage; 144bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 145bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Controller mController; 146bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private ControllerResultUiThreadWrapper<ControllerResults> mControllerCallback; 147bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 148bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // contains the HTML body. Is used by LoadAttachmentTask to display inline images. 149bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // is null most of the time, is used transiently to pass info to LoadAttachementTask 150bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private String mHtmlTextRaw; 151bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 152bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // contains the HTML content as set in WebView. 153bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private String mHtmlTextWebView; 154bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 155bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mIsMessageLoadedForTest; 156bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 157bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MessageObserver mMessageObserver; 158bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 159bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final int CONTACT_STATUS_STATE_UNLOADED = 0; 160bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final int CONTACT_STATUS_STATE_UNLOADED_TRIGGERED = 1; 161bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final int CONTACT_STATUS_STATE_LOADED = 2; 162bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 163bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int mContactStatusState; 164bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Uri mQuickContactLookupUri; 165bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 166bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Flag for {@link #mTabFlags}: Message has attachment(s) */ 167bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected static final int TAB_FLAGS_HAS_ATTACHMENT = 1; 168bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 169bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 170bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Flag for {@link #mTabFlags}: Message contains invite. This flag is only set by 171bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * {@link MessageViewFragment}. 172bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 173bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected static final int TAB_FLAGS_HAS_INVITE = 2; 174bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 175bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Flag for {@link #mTabFlags}: Message contains pictures */ 176bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected static final int TAB_FLAGS_HAS_PICTURES = 4; 177bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 178bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Flag for {@link #mTabFlags}: "Show pictures" has already been pressed */ 179bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected static final int TAB_FLAGS_PICTURE_LOADED = 8; 180bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 181bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 182bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Flags to control the tabs. 183bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @see #updateTabs(int) 184bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 185bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int mTabFlags; 186bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 187bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** # of attachments in the current message */ 188bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int mAttachmentCount; 189bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 190bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Use (random) large values, to avoid confusion with TAB_FLAGS_* 191bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected static final int TAB_MESSAGE = 101; 192bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected static final int TAB_INVITE = 102; 193bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected static final int TAB_ATTACHMENT = 103; 194bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final int TAB_NONE = 0; 195bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 196bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Current tab */ 197bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int mCurrentTab = TAB_NONE; 198bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 199bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Tab that was selected in the previous activity instance. 200bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Used to restore the current tab after screen rotation. 201bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 202bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int mRestoredTab = TAB_NONE; 203bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 204bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mRestoredPictureLoaded; 205bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 206bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker(); 207bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 208bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public interface Callback { 209bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 210bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when a link in a message is clicked. 211bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 212bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param url link url that's clicked. 213bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true if handled, false otherwise. 214bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 215bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onUrlInMessageClicked(String url); 216bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 217bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 218bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when the message specified doesn't exist, or is deleted/moved. 219bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 220bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onMessageNotExists(); 221bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 222bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Called when it starts loading a message. */ 223bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onLoadMessageStarted(); 224bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 225bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Called when it successfully finishes loading a message. */ 226bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onLoadMessageFinished(); 227bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 228bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Called when an error occurred during loading a message. */ 229bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onLoadMessageError(String errorMessage); 230bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 231bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 232bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public static class EmptyCallback implements Callback { 233bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public static final Callback INSTANCE = new EmptyCallback(); 234bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override public void onLoadMessageError(String errorMessage) {} 235bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override public void onLoadMessageFinished() {} 236bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override public void onLoadMessageStarted() {} 237bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override public void onMessageNotExists() {} 238bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 239bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onUrlInMessageClicked(String url) { 240bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 241bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 242bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 243bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 244bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Callback mCallback = EmptyCallback.INSTANCE; 245bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 246bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 247bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onAttach(Activity activity) { 248bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 249bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onAttach"); 250bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 251bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onAttach(activity); 252bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 253bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 254bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 255bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onCreate(Bundle savedInstanceState) { 256bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 257bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onCreate"); 258bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 259bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onCreate(savedInstanceState); 260bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 261bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContext = getActivity().getApplicationContext(); 262bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 263bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Initialize components, but don't "start" them. Registering the controller callbacks 264bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // and starting MessageObserver, should be done in onActivityCreated or later and be stopped 265bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // in onDestroyView to prevent from getting callbacks when the fragment is in the back 266bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // stack, but they'll start again when it's back from the back stack. 267bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController = Controller.getInstance(mContext); 268bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mControllerCallback = new ControllerResultUiThreadWrapper<ControllerResults>( 269bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new Handler(), new ControllerResults()); 270bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageObserver = new MessageObserver(new Handler(), mContext); 271bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 272bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (savedInstanceState != null) { 273bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook restoreInstanceState(savedInstanceState); 274bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 275bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 276bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 277bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 278bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public View onCreateView( 279bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 280bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 281bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onCreateView"); 282bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 283bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final View view = inflater.inflate(R.layout.message_view_fragment, container, false); 284bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 285bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cleanupDetachedViews(); 286bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 287bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSubjectView = (TextView) UiUtilities.getView(view, R.id.subject); 288bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromNameView = (TextView) UiUtilities.getView(view, R.id.from_name); 289bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromAddressView = (TextView) UiUtilities.getView(view, R.id.from_address); 290bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAddressesView = (TextView) UiUtilities.getView(view, R.id.addresses); 291bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDateTimeView = (TextView) UiUtilities.getView(view, R.id.datetime); 292bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageContentView = (WebView) UiUtilities.getView(view, R.id.message_content); 293bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachments = (LinearLayout) UiUtilities.getView(view, R.id.attachments); 294bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mTabSection = UiUtilities.getView(view, R.id.message_tabs_section); 295bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromBadge = (ImageView) UiUtilities.getView(view, R.id.badge); 296bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSenderPresenceView = (ImageView) UiUtilities.getView(view, R.id.presence); 297bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMainView = UiUtilities.getView(view, R.id.main_panel); 298bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mLoadingProgress = UiUtilities.getView(view, R.id.loading_progress); 299bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDetailsCollapsed = UiUtilities.getView(view, R.id.sub_header_contents_collapsed); 300bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDetailsExpanded = UiUtilities.getView(view, R.id.sub_header_contents_expanded); 301bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 302bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromNameView.setOnClickListener(this); 303bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromAddressView.setOnClickListener(this); 304bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromBadge.setOnClickListener(this); 305bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSenderPresenceView.setOnClickListener(this); 306bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 307bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageTab = UiUtilities.getView(view, R.id.show_message); 308bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachmentTab = UiUtilities.getView(view, R.id.show_attachments); 309bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mShowPicturesTab = UiUtilities.getView(view, R.id.show_pictures); 310bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAlwaysShowPicturesButton = UiUtilities.getView(view, R.id.always_show_pictures_button); 311bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Invite is only used in MessageViewFragment, but visibility is controlled here. 312bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mInviteTab = UiUtilities.getView(view, R.id.show_invite); 313bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 314bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageTab.setOnClickListener(this); 315bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachmentTab.setOnClickListener(this); 316bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mShowPicturesTab.setOnClickListener(this); 317bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAlwaysShowPicturesButton.setOnClickListener(this); 318bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mInviteTab.setOnClickListener(this); 319bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDetailsCollapsed.setOnClickListener(this); 320bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDetailsExpanded.setOnClickListener(this); 321bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 322bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachmentsScroll = UiUtilities.getView(view, R.id.attachments_scroll); 323bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mInviteScroll = UiUtilities.getView(view, R.id.invite_scroll); 324bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 325bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook WebSettings webSettings = mMessageContentView.getSettings(); 326bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean supportMultiTouch = mContext.getPackageManager() 327bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH); 328bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook webSettings.setDisplayZoomControls(!supportMultiTouch); 329bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook webSettings.setSupportZoom(true); 330bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook webSettings.setBuiltInZoomControls(true); 331bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageContentView.setWebViewClient(new CustomWebViewClient()); 332bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return view; 333bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 334bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 335bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 336bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onActivityCreated(Bundle savedInstanceState) { 337bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 338bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onActivityCreated"); 339bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 340bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onActivityCreated(savedInstanceState); 341bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController.addResultCallback(mControllerCallback); 342bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 343bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook resetView(); 344bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new LoadMessageTask(true).executeParallel(); 345bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 346bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook UiUtilities.installFragment(this); 347bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 348bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 349bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 350bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onStart() { 351bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 352bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onStart"); 353bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 354bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onStart(); 355bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 356bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 357bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 358bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onResume() { 359bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 360bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onResume"); 361bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 362bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onResume(); 363bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 364bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // We might have comes back from other full-screen activities. If so, we need to update 365bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // the attachment tab as system settings may have been updated that affect which 366bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // options are available to the user. 367bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateAttachmentTab(); 368bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 369bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 370bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 371bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onPause() { 372bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 373bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onPause"); 374bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 375bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onPause(); 376bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 377bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 378bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 379bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onStop() { 380bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 381bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onStop"); 382bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 383bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onStop(); 384bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 385bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 386bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 387bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDestroyView() { 388bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 389bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onDestroyView"); 390bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 391bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook UiUtilities.uninstallFragment(this); 392bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController.removeResultCallback(mControllerCallback); 393bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cancelAllTasks(); 394bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 395bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // We should clean up the Webview here, but it can't release resources until it is 396bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // actually removed from the view tree. 397bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 398bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onDestroyView(); 399bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 400bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 401bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void cleanupDetachedViews() { 402bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // WebView cleanup must be done after it leaves the rendering tree, according to 403bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // its contract 404bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mMessageContentView != null) { 405bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageContentView.destroy(); 406bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageContentView = null; 407bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 408bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 409bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 410bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 411bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDestroy() { 412bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 413bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onDestroy"); 414bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 415bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 416bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cleanupDetachedViews(); 417bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onDestroy(); 418bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 419bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 420bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 421bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDetach() { 422bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 423bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onDetach"); 424bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 425bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onDetach(); 426bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 427bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 428bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 429bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onSaveInstanceState(Bundle outState) { 430bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 431bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onSaveInstanceState"); 432bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 433bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onSaveInstanceState(outState); 434bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook outState.putInt(BUNDLE_KEY_CURRENT_TAB, mCurrentTab); 435bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook outState.putBoolean(BUNDLE_KEY_PICTURE_LOADED, (mTabFlags & TAB_FLAGS_PICTURE_LOADED) != 0); 436bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 437bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 438bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void restoreInstanceState(Bundle state) { 439bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 440bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " restoreInstanceState"); 441bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 442bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // At this point (in onCreate) no tabs are visible (because we don't know if the message has 443bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // an attachment or invite before loading it). We just remember the tab here. 444bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // We'll make it current when the tab first becomes visible in updateTabs(). 445bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRestoredTab = state.getInt(BUNDLE_KEY_CURRENT_TAB); 446bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRestoredPictureLoaded = state.getBoolean(BUNDLE_KEY_PICTURE_LOADED); 447bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 448bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 449bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void setCallback(Callback callback) { 450bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback = (callback == null) ? EmptyCallback.INSTANCE : callback; 451bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 452bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 453bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void cancelAllTasks() { 454bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageObserver.unregister(); 455bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mTaskTracker.cancellAllInterrupt(); 456bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 457bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 458bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected final Controller getController() { 459bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mController; 460bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 461bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 462bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected final Callback getCallback() { 463bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mCallback; 464bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 465bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 466bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public final Message getMessage() { 467bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mMessage; 468bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 469bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 470bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected final boolean isMessageOpen() { 471bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mMessage != null; 472bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 473bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 474bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 475bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Returns the account id of the current message, or -1 if unknown (message not open yet, or 476bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * viewing an EML message). 477bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 478bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public long getAccountId() { 479bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mAccountId; 480bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 481bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 482bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 483bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Show/hide the content. We hide all the content (except for the bottom buttons) when loading, 484bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * to avoid flicker. 485bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 486bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void showContent(boolean showContent, boolean showProgressWhenHidden) { 487bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(mMainView, showContent); 488bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(mLoadingProgress, !showContent && showProgressWhenHidden); 489bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 490bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 491bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // TODO: clean this up - most of this is not needed since the WebView and Fragment is not 492bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // reused for multiple messages. 493bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void resetView() { 494bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showContent(false, false); 495bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateTabs(0); 496bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setCurrentTab(TAB_MESSAGE); 497bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mMessageContentView != null) { 498bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook blockNetworkLoads(true); 499bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageContentView.scrollTo(0, 0); 500bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 501bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Dynamic configuration of WebView 502bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final WebSettings settings = mMessageContentView.getSettings(); 503bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); 504bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageContentView.setInitialScale(getWebViewZoom()); 505bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 506bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachmentsScroll.scrollTo(0, 0); 507bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mInviteScroll.scrollTo(0, 0); 508bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachments.removeAllViews(); 509bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachments.setVisibility(View.GONE); 510bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook initContactStatusViews(); 511bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 512bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 513bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 514bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Returns the zoom scale (in percent) which is a combination of the user setting 515bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * (tiny, small, normal, large, huge) and the device density. The intention 516bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * is for the text to be physically equal in size over different density 517bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * screens. 518bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 519bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int getWebViewZoom() { 520bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook float density = mContext.getResources().getDisplayMetrics().density; 521bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int zoom = Preferences.getPreferences(mContext).getTextZoom(); 522bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (sZoomSizes == null) { 523bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sZoomSizes = mContext.getResources() 524bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook .getStringArray(R.array.general_preference_text_zoom_size); 525bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 526bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return (int)(Float.valueOf(sZoomSizes[zoom]) * density * 100); 527bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 528bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 529bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void initContactStatusViews() { 530bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContactStatusState = CONTACT_STATUS_STATE_UNLOADED; 531bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mQuickContactLookupUri = null; 532bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showDefaultQuickContactBadgeImage(); 533bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 534bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 535bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void showDefaultQuickContactBadgeImage() { 536bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromBadge.setImageResource(R.drawable.ic_contact_picture); 537bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 538bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 539bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected final void addTabFlags(int tabFlags) { 540bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateTabs(mTabFlags | tabFlags); 541bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 542bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 543bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final void clearTabFlags(int tabFlags) { 544bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateTabs(mTabFlags & ~tabFlags); 545bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 546bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 547bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void setAttachmentCount(int count) { 548bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachmentCount = count; 549bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mAttachmentCount > 0) { 550bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook addTabFlags(TAB_FLAGS_HAS_ATTACHMENT); 551bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 552bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook clearTabFlags(TAB_FLAGS_HAS_ATTACHMENT); 553bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 554bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 555bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 556bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static void makeVisible(View v, boolean visible) { 557bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final int visibility = visible ? View.VISIBLE : View.GONE; 558bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if ((v != null) && (v.getVisibility() != visibility)) { 559bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook v.setVisibility(visibility); 560bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 561bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 562bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 563bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static boolean isVisible(View v) { 564bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return (v != null) && (v.getVisibility() == View.VISIBLE); 565bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 566bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 567bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 568bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Update the visual of the tabs. (visibility, text, etc) 569bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 570bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void updateTabs(int tabFlags) { 571bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mTabFlags = tabFlags; 572bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 573bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (getView() == null) { 574bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 575bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 576bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 577bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean messageTabVisible = (tabFlags & (TAB_FLAGS_HAS_INVITE | TAB_FLAGS_HAS_ATTACHMENT)) 578bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook != 0; 579bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(mMessageTab, messageTabVisible); 580bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(mInviteTab, (tabFlags & TAB_FLAGS_HAS_INVITE) != 0); 581bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(mAttachmentTab, (tabFlags & TAB_FLAGS_HAS_ATTACHMENT) != 0); 582bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 583bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final boolean hasPictures = (tabFlags & TAB_FLAGS_HAS_PICTURES) != 0; 584bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final boolean pictureLoaded = (tabFlags & TAB_FLAGS_PICTURE_LOADED) != 0; 585bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(mShowPicturesTab, hasPictures && !pictureLoaded); 586bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 587bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachmentTab.setText(mContext.getResources().getQuantityString( 588bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook R.plurals.message_view_show_attachments_action, 589bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachmentCount, mAttachmentCount)); 590bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 591bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Hide the entire section if no tabs are visible. 592bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(mTabSection, isVisible(mMessageTab) || isVisible(mInviteTab) 593bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook || isVisible(mAttachmentTab) || isVisible(mShowPicturesTab) 594bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook || isVisible(mAlwaysShowPicturesButton)); 595bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 596bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Restore previously selected tab after rotation 597bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mRestoredTab != TAB_NONE && isVisible(getTabViewForFlag(mRestoredTab))) { 598bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setCurrentTab(mRestoredTab); 599bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRestoredTab = TAB_NONE; 600bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 601bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 602bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 603bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 604bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Set the current tab. 605bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 606bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param tab any of {@link #TAB_MESSAGE}, {@link #TAB_ATTACHMENT} or {@link #TAB_INVITE}. 607bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 608bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void setCurrentTab(int tab) { 609bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCurrentTab = tab; 610bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 611bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Hide & unselect all tabs 612bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(getTabContentViewForFlag(TAB_MESSAGE), false); 613bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(getTabContentViewForFlag(TAB_ATTACHMENT), false); 614bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(getTabContentViewForFlag(TAB_INVITE), false); 615bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook getTabViewForFlag(TAB_MESSAGE).setSelected(false); 616bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook getTabViewForFlag(TAB_ATTACHMENT).setSelected(false); 617bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook getTabViewForFlag(TAB_INVITE).setSelected(false); 618bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 619bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(getTabContentViewForFlag(mCurrentTab), true); 620bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook getTabViewForFlag(mCurrentTab).setSelected(true); 621bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 622bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 623bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View getTabViewForFlag(int tabFlag) { 624bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (tabFlag) { 625bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case TAB_MESSAGE: 626bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mMessageTab; 627bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case TAB_ATTACHMENT: 628bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mAttachmentTab; 629bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case TAB_INVITE: 630bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mInviteTab; 631bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 632bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook throw new IllegalArgumentException(); 633bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 634bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 635bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View getTabContentViewForFlag(int tabFlag) { 636bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (tabFlag) { 637bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case TAB_MESSAGE: 638bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mMessageContentView; 639bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case TAB_ATTACHMENT: 640bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mAttachmentsScroll; 641bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case TAB_INVITE: 642bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mInviteScroll; 643bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 644bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook throw new IllegalArgumentException(); 645bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 646bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 647bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void blockNetworkLoads(boolean block) { 648bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mMessageContentView != null) { 649bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageContentView.getSettings().setBlockNetworkLoads(block); 650bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 651bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 652bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 653bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void setMessageHtml(String html) { 654bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (html == null) { 655bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook html = ""; 656bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 657bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mMessageContentView != null) { 658bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageContentView.loadDataWithBaseURL("email://", html, "text/html", "utf-8", null); 659bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 660bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 661bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 662bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 663bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Handle clicks on sender, which shows {@link QuickContact} or prompts to add 664bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * the sender as a contact. 665bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 666bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onClickSender() { 667bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!isMessageOpen()) return; 668bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final Address senderEmail = Address.unpackFirst(mMessage.mFrom); 669bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (senderEmail == null) return; 670bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 671bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mContactStatusState == CONTACT_STATUS_STATE_UNLOADED) { 672bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Status not loaded yet. 673bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContactStatusState = CONTACT_STATUS_STATE_UNLOADED_TRIGGERED; 674bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 675bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 676bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mContactStatusState == CONTACT_STATUS_STATE_UNLOADED_TRIGGERED) { 677bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; // Already clicked, and waiting for the data. 678bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 679bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 680bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mQuickContactLookupUri != null) { 681bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook QuickContact.showQuickContact(mContext, mFromBadge, mQuickContactLookupUri, 682bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook QuickContact.MODE_MEDIUM, null); 683bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 684bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // No matching contact, ask user to create one 685bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final Uri mailUri = Uri.fromParts("mailto", senderEmail.getAddress(), null); 686bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final Intent intent = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT, 687bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mailUri); 688bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 689bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Only provide personal name hint if we have one 690bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final String senderPersonal = senderEmail.getPersonal(); 691bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!TextUtils.isEmpty(senderPersonal)) { 692bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook intent.putExtra(ContactsContract.Intents.Insert.NAME, senderPersonal); 693bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 694bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 695bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 696bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook startActivity(intent); 697bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 698bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 699bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 700bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static class ContactStatusLoaderCallbacks 701bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook implements LoaderCallbacks<ContactStatusLoader.Result> { 702bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final String BUNDLE_EMAIL_ADDRESS = "email"; 703bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final MessageViewFragmentBase mFragment; 704bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 705bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public ContactStatusLoaderCallbacks(MessageViewFragmentBase fragment) { 706bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFragment = fragment; 707bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 708bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 709bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public static Bundle createArguments(String emailAddress) { 710bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Bundle b = new Bundle(); 711bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook b.putString(BUNDLE_EMAIL_ADDRESS, emailAddress); 712bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return b; 713bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 714bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 715bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 716bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public Loader<ContactStatusLoader.Result> onCreateLoader(int id, Bundle args) { 717bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return new ContactStatusLoader(mFragment.mContext, 718bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook args.getString(BUNDLE_EMAIL_ADDRESS)); 719bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 720bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 721bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 722bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onLoadFinished(Loader<ContactStatusLoader.Result> loader, 723bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ContactStatusLoader.Result result) { 724bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean triggered = 725bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook (mFragment.mContactStatusState == CONTACT_STATUS_STATE_UNLOADED_TRIGGERED); 726bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFragment.mContactStatusState = CONTACT_STATUS_STATE_LOADED; 727bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFragment.mQuickContactLookupUri = result.mLookupUri; 728bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 729bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (result.isUnknown()) { 730bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFragment.mSenderPresenceView.setVisibility(View.GONE); 731bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 732bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFragment.mSenderPresenceView.setVisibility(View.VISIBLE); 733bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFragment.mSenderPresenceView.setImageResource(result.mPresenceResId); 734bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 735bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (result.mPhoto != null) { // photo will be null if unknown. 736bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFragment.mFromBadge.setImageBitmap(result.mPhoto); 737bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 738bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (triggered) { 739bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFragment.onClickSender(); 740bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 741bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 742bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 743bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 744bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onLoaderReset(Loader<ContactStatusLoader.Result> loader) { 745bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 746bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 747bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 748bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onSaveAttachment(MessageViewAttachmentInfo info) { 749bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!Utility.isExternalStorageMounted()) { 750bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /* 751bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Abort early if there's no place to save the attachment. We don't want to spend 752bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * the time downloading it and then abort. 753bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 754bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.showToast(getActivity(), R.string.message_view_status_attachment_not_saved); 755bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 756bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 757bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 758bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (info.isFileSaved()) { 759bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Nothing to do - we have the file saved. 760bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 761bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 762bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 763bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook File savedFile = performAttachmentSave(info); 764bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (savedFile != null) { 765bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.showToast(getActivity(), String.format( 766bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContext.getString(R.string.message_view_status_attachment_saved), 767bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook savedFile.getName())); 768bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 769bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.showToast(getActivity(), R.string.message_view_status_attachment_not_saved); 770bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 771bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 772bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 773bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private File performAttachmentSave(MessageViewAttachmentInfo info) { 774bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Attachment attachment = Attachment.restoreAttachmentWithId(mContext, info.mId); 775bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Uri attachmentUri = AttachmentUtilities.getAttachmentUri(mAccountId, attachment.mId); 776bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 777bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook try { 778bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook File downloads = Environment.getExternalStoragePublicDirectory( 779bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Environment.DIRECTORY_DOWNLOADS); 780bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook downloads.mkdirs(); 781bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook File file = Utility.createUniqueFile(downloads, attachment.mFileName); 782bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Uri contentUri = AttachmentUtilities.resolveAttachmentIdToContentUri( 783bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContext.getContentResolver(), attachmentUri); 784bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook InputStream in = mContext.getContentResolver().openInputStream(contentUri); 785bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook OutputStream out = new FileOutputStream(file); 786bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook IOUtils.copy(in, out); 787bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook out.flush(); 788bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook out.close(); 789bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook in.close(); 790bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 791bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String absolutePath = file.getAbsolutePath(); 792bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 793bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Although the download manager can scan media files, scanning only happens after the 794bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // user clicks on the item in the Downloads app. So, we run the attachment through 795bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // the media scanner ourselves so it gets added to gallery / music immediately. 796bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MediaScannerConnection.scanFile(mContext, new String[] {absolutePath}, 797bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook null, null); 798bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 799bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook DownloadManager dm = 800bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE); 801bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook dm.addCompletedDownload(info.mName, info.mName, 802bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook false /* do not use media scanner */, 803bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook info.mContentType, absolutePath, info.mSize, 804bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook true /* show notification */); 805bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 806bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Cache the stored file information. 807bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook info.setSavedPath(absolutePath); 808bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 809bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Update our buttons. 810bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateAttachmentButtons(info); 811bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 812bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return file; 813bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 814bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } catch (IOException ioe) { 815bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Ignore. Callers will handle it from the return code. 816bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 817bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 818bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return null; 819bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 820bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 821bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onOpenAttachment(MessageViewAttachmentInfo info) { 822bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (info.mAllowInstall) { 823bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // The package installer is unable to install files from a content URI; it must be 824bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // given a file path. Therefore, we need to save it first in order to proceed 825bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!info.mAllowSave || !Utility.isExternalStorageMounted()) { 826bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.showToast(getActivity(), R.string.message_view_status_attachment_not_saved); 827bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 828bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 829bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 830bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!info.isFileSaved()) { 831bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (performAttachmentSave(info) == null) { 832bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Saving failed for some reason - bail. 833bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.showToast( 834bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook getActivity(), R.string.message_view_status_attachment_not_saved); 835bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 836bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 837bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 838bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 839bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook try { 840bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Intent intent = info.getAttachmentIntent(mContext, mAccountId); 841bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook startActivity(intent); 842bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } catch (ActivityNotFoundException e) { 843bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.showToast(getActivity(), R.string.message_view_display_attachment_toast); 844bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 845bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 846bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 847bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onInfoAttachment(final MessageViewAttachmentInfo attachment) { 848bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook AttachmentInfoDialog dialog = 849bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook AttachmentInfoDialog.newInstance(getActivity(), attachment.mDenyFlags); 850bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook dialog.show(getActivity().getFragmentManager(), null); 851bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 852bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 853bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onLoadAttachment(final MessageViewAttachmentInfo attachment) { 854bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.loadButton.setVisibility(View.GONE); 855bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // If there's nothing in the download queue, we'll probably start right away so wait a 856bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // second before showing the cancel button 857bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (AttachmentDownloadService.getQueueSize() == 0) { 858bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Set to invisible; if the button is still in this state one second from now, we'll 859bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // assume the download won't start right away, and we make the cancel button visible 860bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.cancelButton.setVisibility(View.GONE); 861bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Create the timed task that will change the button state 862bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new EmailAsyncTask<Void, Void, Void>(mTaskTracker) { 863bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 864bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected Void doInBackground(Void... params) { 865bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook try { 866bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Thread.sleep(1000L); 867bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } catch (InterruptedException e) { } 868bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return null; 869bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 870bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 871bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void onSuccess(Void result) { 872bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // If the timeout completes and the attachment has not loaded, show cancel 873bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!attachment.loaded) { 874bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.cancelButton.setVisibility(View.VISIBLE); 875bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 876bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 877bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook }.executeParallel(); 878bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 879bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.cancelButton.setVisibility(View.VISIBLE); 880bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 881bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.showProgressIndeterminate(); 882bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController.loadAttachment(attachment.mId, mMessageId, mAccountId); 883bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 884bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 885bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onCancelAttachment(MessageViewAttachmentInfo attachment) { 886bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Don't change button states if we couldn't cancel the download 887bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (AttachmentDownloadService.cancelQueuedAttachment(attachment.mId)) { 888bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.loadButton.setVisibility(View.VISIBLE); 889bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.cancelButton.setVisibility(View.GONE); 890bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.hideProgress(); 891bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 892bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 893bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 894bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 895bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called by ControllerResults. Show the "View" and "Save" buttons; hide "Load" and "Stop" 896bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 897bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param attachmentId the attachment that was just downloaded 898bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 899bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void doFinishLoadAttachment(long attachmentId) { 900bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageViewAttachmentInfo info = findAttachmentInfo(attachmentId); 901bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (info != null) { 902bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook info.loaded = true; 903bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateAttachmentButtons(info); 904bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 905bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 906bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 907bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void showPicturesInHtml() { 908bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean picturesAlreadyLoaded = (mTabFlags & TAB_FLAGS_PICTURE_LOADED) != 0; 909bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if ((mMessageContentView != null) && !picturesAlreadyLoaded) { 910bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook blockNetworkLoads(false); 911bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // TODO: why is this calling setMessageHtml just because the images can load now? 912bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setMessageHtml(mHtmlTextWebView); 913bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 914bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Prompt the user to always show images from this sender. 915bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(UiUtilities.getView(getView(), R.id.always_show_pictures_button), true); 916bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 917bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook addTabFlags(TAB_FLAGS_PICTURE_LOADED); 918bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 919bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 920bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 921bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void showDetails() { 922bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!isMessageOpen()) { 923bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 924bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 925bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 926bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!mDetailsFilled) { 927bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String date = formatDate(mMessage.mTimeStamp, true); 928bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final String SEPARATOR = "\n"; 929bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String to = Address.toString(Address.unpack(mMessage.mTo), SEPARATOR); 930bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String cc = Address.toString(Address.unpack(mMessage.mCc), SEPARATOR); 931bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String bcc = Address.toString(Address.unpack(mMessage.mBcc), SEPARATOR); 932bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setDetailsRow(mDetailsExpanded, date, R.id.date, R.id.date_row); 933bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setDetailsRow(mDetailsExpanded, to, R.id.to, R.id.to_row); 934bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setDetailsRow(mDetailsExpanded, cc, R.id.cc, R.id.cc_row); 935bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setDetailsRow(mDetailsExpanded, bcc, R.id.bcc, R.id.bcc_row); 936bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDetailsFilled = true; 937bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 938bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 939bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDetailsCollapsed.setVisibility(View.GONE); 940bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDetailsExpanded.setVisibility(View.VISIBLE); 941bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 942bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 943bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void hideDetails() { 944bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDetailsCollapsed.setVisibility(View.VISIBLE); 945bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDetailsExpanded.setVisibility(View.GONE); 946bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 947bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 948bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static void setDetailsRow(View root, String text, int textViewId, int rowViewId) { 949bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (TextUtils.isEmpty(text)) { 950bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook root.findViewById(rowViewId).setVisibility(View.GONE); 951bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 952bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 953bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ((TextView) UiUtilities.getView(root, textViewId)).setText(text); 954bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 955bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 956bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 957bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 958bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onClick(View view) { 959bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!isMessageOpen()) { 960bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; // Ignore. 961bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 962bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (view.getId()) { 963bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.badge: 964bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onClickSender(); 965bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 966bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.load: 967bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onLoadAttachment((MessageViewAttachmentInfo) view.getTag()); 968bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 969bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.info: 970bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onInfoAttachment((MessageViewAttachmentInfo) view.getTag()); 971bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 972bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.save: 973bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onSaveAttachment((MessageViewAttachmentInfo) view.getTag()); 974bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 975bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.open: 976bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onOpenAttachment((MessageViewAttachmentInfo) view.getTag()); 977bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 978bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.cancel: 979bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onCancelAttachment((MessageViewAttachmentInfo) view.getTag()); 980bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 981bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.show_message: 982bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setCurrentTab(TAB_MESSAGE); 983bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 984bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.show_invite: 985bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setCurrentTab(TAB_INVITE); 986bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 987bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.show_attachments: 988bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setCurrentTab(TAB_ATTACHMENT); 989bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 990bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.show_pictures: 991bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showPicturesInHtml(); 992bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 993bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.always_show_pictures_button: 994bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setShowImagesForSender(); 995bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 996bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.sub_header_contents_collapsed: 997bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showDetails(); 998bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 999bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.sub_header_contents_expanded: 1000bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook hideDetails(); 1001bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1002bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1003bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1004bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1005bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1006bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Start loading contact photo and presence. 1007bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1008bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void queryContactStatus() { 1009bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!isMessageOpen()) return; 1010bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook initContactStatusViews(); // Initialize the state, just in case. 1011bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1012bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Find the sender email address, and start presence check. 1013bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Address sender = Address.unpackFirst(mMessage.mFrom); 1014bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (sender != null) { 1015bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String email = sender.getAddress(); 1016bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (email != null) { 1017bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook getLoaderManager().restartLoader(PHOTO_LOADER_ID, 1018bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ContactStatusLoaderCallbacks.createArguments(email), 1019bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new ContactStatusLoaderCallbacks(this)); 1020bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1021bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1022bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1023bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1024bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1025bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called by {@link LoadMessageTask} and {@link ReloadMessageTask} to load a message in a 1026bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * subclass specific way. 1027bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1028bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * NOTE This method is called on a worker thread! Implementations must properly synchronize 1029bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * when accessing members. 1030bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1031bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param activity the parent activity. Subclass use it as a context, and to show a toast. 1032bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1033bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected abstract Message openMessageSync(Activity activity); 1034bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1035bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1036bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called in a background thread to reload a new copy of the Message in case something has 1037bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * changed. 1038bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1039bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected Message reloadMessageSync(Activity activity) { 1040bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return openMessageSync(activity); 1041bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1042bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1043bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1044bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Async task for loading a single message outside of the UI thread 1045bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1046bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class LoadMessageTask extends EmailAsyncTask<Void, Void, Message> { 1047bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1048bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final boolean mOkToFetch; 1049bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Mailbox mMailbox; 1050bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1051bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1052bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Special constructor to cache some local info 1053bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1054bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public LoadMessageTask(boolean okToFetch) { 1055bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(mTaskTracker); 1056bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mOkToFetch = okToFetch; 1057bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1058bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1059bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1060bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected Message doInBackground(Void... params) { 1061bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Activity activity = getActivity(); 1062bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Message message = null; 1063bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (activity != null) { 1064bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook message = openMessageSync(activity); 1065bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1066bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (message != null) { 1067bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey); 1068bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mMailbox == null) { 1069bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook message = null; // mailbox removed?? 1070bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1071bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1072bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return message; 1073bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1074bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1075bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1076bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void onSuccess(Message message) { 1077bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (message == null) { 1078bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook resetView(); 1079bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onMessageNotExists(); 1080bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1081bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1082bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageId = message.mId; 1083bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1084bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook reloadUiFromMessage(message, mOkToFetch); 1085bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook queryContactStatus(); 1086bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onMessageShown(mMessageId, mMailbox); 1087bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook RecentMailboxManager.getInstance(mContext).touch(mAccountId, message.mMailboxKey); 1088bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1089bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1090bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1091bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1092bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Kicked by {@link MessageObserver}. Reload the message and update the views. 1093bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1094bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class ReloadMessageTask extends EmailAsyncTask<Void, Void, Message> { 1095bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public ReloadMessageTask() { 1096bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(mTaskTracker); 1097bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1098bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1099bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1100bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected Message doInBackground(Void... params) { 1101bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Activity activity = getActivity(); 1102bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (activity == null) { 1103bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return null; 1104bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1105bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return reloadMessageSync(activity); 1106bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1107bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1108bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1109bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1110bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void onSuccess(Message message) { 1111bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (message == null || message.mMailboxKey != mMessage.mMailboxKey) { 1112bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Message deleted or moved. 1113bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onMessageNotExists(); 1114bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1115bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1116bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessage = message; 1117bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateHeaderView(mMessage); 1118bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1119bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1120bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1121bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1122bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when a message is shown to the user. 1123bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1124bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void onMessageShown(long messageId, Mailbox mailbox) { 1125bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1126bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1127bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1128bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when the message body is loaded. 1129bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1130bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void onPostLoadBody() { 1131bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1132bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1133bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1134bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Async task for loading a single message body outside of the UI thread 1135bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1136bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class LoadBodyTask extends EmailAsyncTask<Void, Void, String[]> { 1137bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1138bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final long mId; 1139bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mErrorLoadingMessageBody; 1140bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final boolean mAutoShowPictures; 1141bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1142bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1143bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Special constructor to cache some local info 1144bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1145bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public LoadBodyTask(long messageId, boolean autoShowPictures) { 1146bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(mTaskTracker); 1147bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mId = messageId; 1148bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAutoShowPictures = autoShowPictures; 1149bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1150bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1151bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1152bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected String[] doInBackground(Void... params) { 1153bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook try { 1154bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String text = null; 1155bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String html = Body.restoreBodyHtmlWithMessageId(mContext, mId); 1156bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (html == null) { 1157bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook text = Body.restoreBodyTextWithMessageId(mContext, mId); 1158bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1159bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return new String[] { text, html }; 1160bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } catch (RuntimeException re) { 1161bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // This catches SQLiteException as well as other RTE's we've seen from the 1162bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // database calls, such as IllegalStateException 1163bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, "Exception while loading message body", re); 1164bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mErrorLoadingMessageBody = true; 1165bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return null; 1166bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1167bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1168bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1169bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1170bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void onSuccess(String[] results) { 1171bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (results == null) { 1172bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mErrorLoadingMessageBody) { 1173bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.showToast(getActivity(), R.string.error_loading_message_body); 1174bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1175bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook resetView(); 1176bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1177bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1178bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook reloadUiFromBody(results[0], results[1], mAutoShowPictures); // text, html 1179bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onPostLoadBody(); 1180bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1181bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1182bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1183bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1184bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Async task for loading attachments 1185bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1186bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Note: This really should only be called when the message load is complete - or, we should 1187bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * leave open a listener so the attachments can fill in as they are discovered. In either case, 1188bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * this implementation is incomplete, as it will fail to refresh properly if the message is 1189bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * partially loaded at this time. 1190bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1191bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class LoadAttachmentsTask extends EmailAsyncTask<Long, Void, Attachment[]> { 1192bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public LoadAttachmentsTask() { 1193bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(mTaskTracker); 1194bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1195bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1196bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1197bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected Attachment[] doInBackground(Long... messageIds) { 1198bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return Attachment.restoreAttachmentsWithMessageId(mContext, messageIds[0]); 1199bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1200bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1201bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1202bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void onSuccess(Attachment[] attachments) { 1203bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook try { 1204bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachments == null) { 1205bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1206bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1207bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean htmlChanged = false; 1208bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int numDisplayedAttachments = 0; 1209bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook for (Attachment attachment : attachments) { 1210bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mHtmlTextRaw != null && attachment.mContentId != null 1211bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook && attachment.mContentUri != null) { 1212bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // for html body, replace CID for inline images 1213bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Regexp which matches ' src="cid:contentId"'. 1214bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String contentIdRe = 1215bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook "\\s+(?i)src=\"cid(?-i):\\Q" + attachment.mContentId + "\\E\""; 1216bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String srcContentUri = " src=\"" + attachment.mContentUri + "\""; 1217bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mHtmlTextRaw = mHtmlTextRaw.replaceAll(contentIdRe, srcContentUri); 1218bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook htmlChanged = true; 1219bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1220bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook addAttachment(attachment); 1221bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook numDisplayedAttachments++; 1222bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1223bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1224bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setAttachmentCount(numDisplayedAttachments); 1225bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mHtmlTextWebView = mHtmlTextRaw; 1226bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mHtmlTextRaw = null; 1227bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (htmlChanged) { 1228bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setMessageHtml(mHtmlTextWebView); 1229bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1230bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } finally { 1231bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showContent(true, false); 1232bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1233bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1234bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1235bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1236bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static Bitmap getPreviewIcon(Context context, AttachmentInfo attachment) { 1237bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook try { 1238bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return BitmapFactory.decodeStream( 1239bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook context.getContentResolver().openInputStream( 1240bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook AttachmentUtilities.getAttachmentThumbnailUri( 1241bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.mAccountKey, attachment.mId, 1242bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook PREVIEW_ICON_WIDTH, 1243bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook PREVIEW_ICON_HEIGHT))); 1244bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } catch (Exception e) { 1245bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, "Attachment preview failed with exception " + e.getMessage()); 1246bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return null; 1247bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1248bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1249bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1250bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1251bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Subclass of AttachmentInfo which includes our views and buttons related to attachment 1252bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * handling, as well as our determination of suitability for viewing (based on availability of 1253bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * a viewer app) and saving (based upon the presence of external storage) 1254bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1255bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static class MessageViewAttachmentInfo extends AttachmentInfo { 1256bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Button openButton; 1257bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Button saveButton; 1258bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Button loadButton; 1259bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Button infoButton; 1260bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Button cancelButton; 1261bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private ImageView iconView; 1262bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1263bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final Map<AttachmentInfo, String> sSavedFileInfos = Maps.newHashMap(); 1264bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1265bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Don't touch it directly from the outer class. 1266bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final ProgressBar mProgressView; 1267bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean loaded; 1268bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1269bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MessageViewAttachmentInfo(Context context, Attachment attachment, 1270bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ProgressBar progressView) { 1271bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(context, attachment); 1272bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mProgressView = progressView; 1273bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1274bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1275bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1276bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Create a new attachment info based upon an existing attachment info. Display 1277bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * related fields (such as views and buttons) are copied from old to new. 1278bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1279bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MessageViewAttachmentInfo(Context context, MessageViewAttachmentInfo oldInfo) { 1280bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(context, oldInfo); 1281bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton = oldInfo.openButton; 1282bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton = oldInfo.saveButton; 1283bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook loadButton = oldInfo.loadButton; 1284bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook infoButton = oldInfo.infoButton; 1285bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cancelButton = oldInfo.cancelButton; 1286bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook iconView = oldInfo.iconView; 1287bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mProgressView = oldInfo.mProgressView; 1288bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook loaded = oldInfo.loaded; 1289bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1290bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1291bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void hideProgress() { 1292bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Don't use GONE, which'll break the layout. 1293bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mProgressView.getVisibility() != View.INVISIBLE) { 1294bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mProgressView.setVisibility(View.INVISIBLE); 1295bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1296bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1297bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1298bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void showProgress(int progress) { 1299bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mProgressView.getVisibility() != View.VISIBLE) { 1300bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mProgressView.setVisibility(View.VISIBLE); 1301bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1302bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mProgressView.isIndeterminate()) { 1303bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mProgressView.setIndeterminate(false); 1304bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1305bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mProgressView.setProgress(progress); 1306bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1307bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Hide on completion. 1308bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (progress == 100) { 1309bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook hideProgress(); 1310bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1311bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1312bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1313bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void showProgressIndeterminate() { 1314bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mProgressView.getVisibility() != View.VISIBLE) { 1315bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mProgressView.setVisibility(View.VISIBLE); 1316bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1317bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!mProgressView.isIndeterminate()) { 1318bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mProgressView.setIndeterminate(true); 1319bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1320bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1321bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1322bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1323bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Determines whether or not this attachment has a saved file in the external storage. That 1324bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * is, the user has at some point clicked "save" for this attachment. 1325bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1326bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Note: this is an approximation and uses an in-memory cache that can get wiped when the 1327bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * process dies, and so is somewhat conservative. Additionally, the user can modify the file 1328bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * after saving, and so the file may not be the same (though this is unlikely). 1329bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1330bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean isFileSaved() { 1331bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String path = getSavedPath(); 1332bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (path == null) { 1333bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 1334bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1335bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean savedFileExists = new File(path).exists(); 1336bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!savedFileExists) { 1337bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Purge the cache entry. 1338bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setSavedPath(null); 1339bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1340bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return savedFileExists; 1341bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1342bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1343bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void setSavedPath(String path) { 1344bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (path == null) { 1345bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sSavedFileInfos.remove(this); 1346bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1347bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sSavedFileInfos.put(this, path); 1348bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1349bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1350bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1351bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1352bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Returns an absolute file path for the given attachment if it has been saved. If one is 1353bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * not found, {@code null} is returned. 1354bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1355bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Clients are expected to validate that the file at the given path is still valid. 1356bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1357bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private String getSavedPath() { 1358bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return sSavedFileInfos.get(this); 1359bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1360bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1361bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1362bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected Uri getUriForIntent(Context context, long accountId) { 1363bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Prefer to act on the saved file for intents. 1364bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String path = getSavedPath(); 1365bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return (path != null) 1366bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ? Uri.parse("file://" + getSavedPath()) 1367bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook : super.getUriForIntent(context, accountId); 1368bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1369bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1370bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1371bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1372bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Updates all current attachments on the attachment tab. 1373bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1374bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void updateAttachmentTab() { 1375bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) { 1376bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook View view = mAttachments.getChildAt(i); 1377bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageViewAttachmentInfo oldInfo = (MessageViewAttachmentInfo)view.getTag(); 1378bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageViewAttachmentInfo newInfo = 1379bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new MessageViewAttachmentInfo(getActivity(), oldInfo); 1380bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateAttachmentButtons(newInfo); 1381bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook view.setTag(newInfo); 1382bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1383bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1384bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1385bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1386bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Updates the attachment buttons. Adjusts the visibility of the buttons as well 1387bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * as updating any tag information associated with the buttons. 1388bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1389bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void updateAttachmentButtons(MessageViewAttachmentInfo attachmentInfo) { 1390bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ImageView attachmentIcon = attachmentInfo.iconView; 1391bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button openButton = attachmentInfo.openButton; 1392bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button saveButton = attachmentInfo.saveButton; 1393bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button loadButton = attachmentInfo.loadButton; 1394bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button infoButton = attachmentInfo.infoButton; 1395bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button cancelButton = attachmentInfo.cancelButton; 1396bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1397bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!attachmentInfo.mAllowView) { 1398bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton.setVisibility(View.GONE); 1399bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1400bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!attachmentInfo.mAllowSave) { 1401bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton.setVisibility(View.GONE); 1402bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1403bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1404bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!attachmentInfo.mAllowView && !attachmentInfo.mAllowSave) { 1405bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // This attachment may never be viewed or saved, so block everything 1406bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.hideProgress(); 1407bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton.setVisibility(View.GONE); 1408bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton.setVisibility(View.GONE); 1409bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook loadButton.setVisibility(View.GONE); 1410bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cancelButton.setVisibility(View.GONE); 1411bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook infoButton.setVisibility(View.VISIBLE); 1412bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else if (attachmentInfo.loaded) { 1413bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // If the attachment is loaded, show 100% progress 1414bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Note that for POP3 messages, the user will only see "Open" and "Save", 1415bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // because the entire message is loaded before being shown. 1416bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Hide "Load" and "Info", show "View" and "Save" 1417bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.showProgress(100); 1418bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachmentInfo.mAllowSave) { 1419bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton.setVisibility(View.VISIBLE); 1420bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1421bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean isFileSaved = attachmentInfo.isFileSaved(); 1422bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton.setEnabled(!isFileSaved); 1423bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!isFileSaved) { 1424bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton.setText(R.string.message_view_attachment_save_action); 1425bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1426bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton.setText(R.string.message_view_attachment_saved); 1427bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1428bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1429bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachmentInfo.mAllowView) { 1430bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Set the attachment action button text accordingly 1431bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachmentInfo.mContentType.startsWith("audio/") || 1432bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.mContentType.startsWith("video/")) { 1433bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton.setText(R.string.message_view_attachment_play_action); 1434bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else if (attachmentInfo.mAllowInstall) { 1435bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton.setText(R.string.message_view_attachment_install_action); 1436bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1437bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton.setText(R.string.message_view_attachment_view_action); 1438bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1439bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton.setVisibility(View.VISIBLE); 1440bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1441bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachmentInfo.mDenyFlags == AttachmentInfo.ALLOW) { 1442bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook infoButton.setVisibility(View.GONE); 1443bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1444bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook infoButton.setVisibility(View.VISIBLE); 1445bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1446bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook loadButton.setVisibility(View.GONE); 1447bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cancelButton.setVisibility(View.GONE); 1448bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1449bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updatePreviewIcon(attachmentInfo); 1450bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1451bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // The attachment is not loaded, so present UI to start downloading it 1452bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1453bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Show "Load"; hide "View", "Save" and "Info" 1454bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton.setVisibility(View.GONE); 1455bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton.setVisibility(View.GONE); 1456bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook infoButton.setVisibility(View.GONE); 1457bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1458bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // If the attachment is queued, show the indeterminate progress bar. From this point,. 1459bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // any progress changes will cause this to be replaced by the normal progress bar 1460bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (AttachmentDownloadService.isAttachmentQueued(attachmentInfo.mId)) { 1461bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.showProgressIndeterminate(); 1462bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook loadButton.setVisibility(View.GONE); 1463bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cancelButton.setVisibility(View.VISIBLE); 1464bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1465bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook loadButton.setVisibility(View.VISIBLE); 1466bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cancelButton.setVisibility(View.GONE); 1467bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1468bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1469bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton.setTag(attachmentInfo); 1470bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton.setTag(attachmentInfo); 1471bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook loadButton.setTag(attachmentInfo); 1472bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook infoButton.setTag(attachmentInfo); 1473bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cancelButton.setTag(attachmentInfo); 1474bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1475bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1476bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1477bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Copy data from a cursor-refreshed attachment into the UI. Called from UI thread. 1478bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1479bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param attachment A single attachment loaded from the provider 1480bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1481bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void addAttachment(Attachment attachment) { 1482bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook LayoutInflater inflater = getActivity().getLayoutInflater(); 1483bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook View view = inflater.inflate(R.layout.message_view_attachment, null); 1484bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1485bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook TextView attachmentName = (TextView) UiUtilities.getView(view, R.id.attachment_name); 1486bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook TextView attachmentInfoView = (TextView) UiUtilities.getView(view, R.id.attachment_info); 1487bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ImageView attachmentIcon = (ImageView) UiUtilities.getView(view, R.id.attachment_icon); 1488bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button openButton = (Button) UiUtilities.getView(view, R.id.open); 1489bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button saveButton = (Button) UiUtilities.getView(view, R.id.save); 1490bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button loadButton = (Button) UiUtilities.getView(view, R.id.load); 1491bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button infoButton = (Button) UiUtilities.getView(view, R.id.info); 1492bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Button cancelButton = (Button) UiUtilities.getView(view, R.id.cancel); 1493bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ProgressBar attachmentProgress = (ProgressBar) UiUtilities.getView(view, R.id.progress); 1494bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1495bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageViewAttachmentInfo attachmentInfo = new MessageViewAttachmentInfo( 1496bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContext, attachment, attachmentProgress); 1497bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1498bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Check whether the attachment already exists 1499bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Utility.attachmentExists(mContext, attachment)) { 1500bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.loaded = true; 1501bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1502bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1503bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.openButton = openButton; 1504bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.saveButton = saveButton; 1505bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.loadButton = loadButton; 1506bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.infoButton = infoButton; 1507bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.cancelButton = cancelButton; 1508bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfo.iconView = attachmentIcon; 1509bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1510bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateAttachmentButtons(attachmentInfo); 1511bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1512bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook view.setTag(attachmentInfo); 1513bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook openButton.setOnClickListener(this); 1514bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook saveButton.setOnClickListener(this); 1515bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook loadButton.setOnClickListener(this); 1516bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook infoButton.setOnClickListener(this); 1517bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cancelButton.setOnClickListener(this); 1518bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1519bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentName.setText(attachmentInfo.mName); 1520bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachmentInfoView.setText(UiUtilities.formatSize(mContext, attachmentInfo.mSize)); 1521bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1522bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachments.addView(view); 1523bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachments.setVisibility(View.VISIBLE); 1524bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1525bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1526bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MessageViewAttachmentInfo findAttachmentInfoFromView(long attachmentId) { 1527bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) { 1528bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageViewAttachmentInfo attachmentInfo = 1529bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook (MessageViewAttachmentInfo) mAttachments.getChildAt(i).getTag(); 1530bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachmentInfo.mId == attachmentId) { 1531bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return attachmentInfo; 1532bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1533bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1534bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return null; 1535bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1536bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1537bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1538bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Reload the UI from a provider cursor. {@link LoadMessageTask#onSuccess} calls it. 1539bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1540bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Update the header views, and start loading the body. 1541bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1542bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param message A copy of the message loaded from the database 1543bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param okToFetch If true, and message is not fully loaded, it's OK to fetch from 1544bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * the network. Use false to prevent looping here. 1545bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1546bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void reloadUiFromMessage(Message message, boolean okToFetch) { 1547bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessage = message; 1548bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAccountId = message.mAccountKey; 1549bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1550bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageObserver.register(ContentUris.withAppendedId(Message.CONTENT_URI, mMessage.mId)); 1551bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1552bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateHeaderView(mMessage); 1553bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1554bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Handle partially-loaded email, as follows: 1555bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // 1. Check value of message.mFlagLoaded 1556bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // 2. If != LOADED, ask controller to load it 1557bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // 3. Controller callback (after loaded) should trigger LoadBodyTask & LoadAttachmentsTask 1558bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // 4. Else start the loader tasks right away (message already loaded) 1559bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (okToFetch && message.mFlagLoaded != Message.FLAG_LOADED_COMPLETE) { 1560bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mControllerCallback.getWrappee().setWaitForLoadMessageId(message.mId); 1561bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController.loadMessageForView(message.mId); 1562bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1563bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Address[] fromList = Address.unpack(mMessage.mFrom); 1564bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean autoShowImages = false; 1565bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook for (Address sender : fromList) { 1566bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String email = sender.getAddress(); 1567bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (shouldShowImagesFor(email)) { 1568bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook autoShowImages = true; 1569bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1570bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1571bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1572bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mControllerCallback.getWrappee().setWaitForLoadMessageId(Message.NO_MESSAGE); 1573bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Ask for body 1574bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new LoadBodyTask(message.mId, autoShowImages).executeParallel(); 1575bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1576bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1577bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1578bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void updateHeaderView(Message message) { 1579bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSubjectView.setText(message.mSubject); 1580bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final Address from = Address.unpackFirst(message.mFrom); 1581bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1582bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Set sender address/display name 1583bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Note we set " " for empty field, so TextView's won't get squashed. 1584bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Otherwise their height will be 0, which breaks the layout. 1585bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (from != null) { 1586bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final String fromFriendly = from.toFriendly(); 1587bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final String fromAddress = from.getAddress(); 1588bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromNameView.setText(fromFriendly); 1589bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromAddressView.setText(fromFriendly.equals(fromAddress) ? " " : fromAddress); 1590bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1591bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromNameView.setText(" "); 1592bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mFromAddressView.setText(" "); 1593bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1594bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDateTimeView.setText(DateUtils.getRelativeTimeSpanString(mContext, message.mTimeStamp) 1595bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook .toString()); 1596bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1597bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // To/Cc/Bcc 1598bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final Resources res = mContext.getResources(); 1599bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final SpannableStringBuilder ssb = new SpannableStringBuilder(); 1600bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final String friendlyTo = Address.toFriendly(Address.unpack(message.mTo)); 1601bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final String friendlyCc = Address.toFriendly(Address.unpack(message.mCc)); 1602bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final String friendlyBcc = Address.toFriendly(Address.unpack(message.mBcc)); 1603bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1604bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!TextUtils.isEmpty(friendlyTo)) { 1605bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.appendBold(ssb, res.getString(R.string.message_view_to_label)); 1606bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ssb.append(" "); 1607bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ssb.append(friendlyTo); 1608bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1609bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!TextUtils.isEmpty(friendlyCc)) { 1610bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ssb.append(" "); 1611bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.appendBold(ssb, res.getString(R.string.message_view_cc_label)); 1612bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ssb.append(" "); 1613bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ssb.append(friendlyCc); 1614bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1615bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!TextUtils.isEmpty(friendlyBcc)) { 1616bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ssb.append(" "); 1617bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.appendBold(ssb, res.getString(R.string.message_view_bcc_label)); 1618bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ssb.append(" "); 1619bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ssb.append(friendlyBcc); 1620bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1621bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAddressesView.setText(ssb); 1622bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1623bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1624bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1625bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return the given date/time in a human readable form. The returned string always have 1626bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * month and day (and year if {@code withYear} is set), so is usually long. 1627bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Use {@link DateUtils#getRelativeTimeSpanString} instead to save the screen real estate. 1628bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1629bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private String formatDate(long millis, boolean withYear) { 1630bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook StringBuilder sb = new StringBuilder(); 1631bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Formatter formatter = new Formatter(sb); 1632bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook DateUtils.formatDateRange(mContext, formatter, millis, millis, 1633bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook DateUtils.FORMAT_SHOW_DATE 1634bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook | DateUtils.FORMAT_ABBREV_ALL 1635bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook | DateUtils.FORMAT_SHOW_TIME 1636bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook | (withYear ? DateUtils.FORMAT_SHOW_YEAR : DateUtils.FORMAT_NO_YEAR)); 1637bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return sb.toString(); 1638bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1639bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1640bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1641bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Reload the body from the provider cursor. This must only be called from the UI thread. 1642bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1643bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param bodyText text part 1644bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param bodyHtml html part 1645bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1646bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * TODO deal with html vs text and many other issues <- WHAT DOES IT MEAN?? 1647bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1648bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void reloadUiFromBody(String bodyText, String bodyHtml, boolean autoShowPictures) { 1649bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String text = null; 1650bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mHtmlTextRaw = null; 1651bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean hasImages = false; 1652bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1653bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (bodyHtml == null) { 1654bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook text = bodyText; 1655bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /* 1656bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Convert the plain text to HTML 1657bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1658bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook StringBuffer sb = new StringBuffer("<html><body>"); 1659bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (text != null) { 1660bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Escape any inadvertent HTML in the text message 1661bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook text = EmailHtmlUtil.escapeCharacterToDisplay(text); 1662bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Find any embedded URL's and linkify 1663bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Matcher m = Patterns.WEB_URL.matcher(text); 1664bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook while (m.find()) { 1665bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int start = m.start(); 1666bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /* 1667bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * WEB_URL_PATTERN may match domain part of email address. To detect 1668bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * this false match, the character just before the matched string 1669bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * should not be '@'. 1670bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1671bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (start == 0 || text.charAt(start - 1) != '@') { 1672bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String url = m.group(); 1673bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Matcher proto = WEB_URL_PROTOCOL.matcher(url); 1674bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String link; 1675bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (proto.find()) { 1676bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // This is work around to force URL protocol part be lower case, 1677bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // because WebView could follow only lower case protocol link. 1678bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook link = proto.group().toLowerCase() + url.substring(proto.end()); 1679bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1680bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Patterns.WEB_URL matches URL without protocol part, 1681bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // so added default protocol to link. 1682bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook link = "http://" + url; 1683bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1684bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String href = String.format("<a href=\"%s\">%s</a>", link, url); 1685bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook m.appendReplacement(sb, href); 1686bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1687bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook else { 1688bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook m.appendReplacement(sb, "$0"); 1689bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1690bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1691bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook m.appendTail(sb); 1692bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1693bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sb.append("</body></html>"); 1694bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook text = sb.toString(); 1695bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1696bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook text = bodyHtml; 1697bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mHtmlTextRaw = bodyHtml; 1698bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook hasImages = IMG_TAG_START_REGEX.matcher(text).find(); 1699bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1700bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1701bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // TODO this is not really accurate. 1702bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // - Images aren't the only network resources. (e.g. CSS) 1703bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // - If images are attached to the email and small enough, we download them at once, 1704bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // and won't need network access when they're shown. 1705bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (hasImages) { 1706bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mRestoredPictureLoaded || autoShowPictures) { 1707bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook blockNetworkLoads(false); 1708bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook addTabFlags(TAB_FLAGS_PICTURE_LOADED); // Set for next onSaveInstanceState 1709bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1710bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Make sure to reset the flag -- otherwise this will keep taking effect even after 1711bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // moving to another message. 1712bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRestoredPictureLoaded = false; 1713bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1714bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook addTabFlags(TAB_FLAGS_HAS_PICTURES); 1715bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1716bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1717bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setMessageHtml(text); 1718bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1719bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Ask for attachments after body 1720bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new LoadAttachmentsTask().executeParallel(mMessage.mId); 1721bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1722bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mIsMessageLoadedForTest = true; 1723bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1724bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1725bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1726bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Overrides for WebView behaviors. 1727bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1728bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class CustomWebViewClient extends WebViewClient { 1729bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1730bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean shouldOverrideUrlLoading(WebView view, String url) { 1731bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mCallback.onUrlInMessageClicked(url); 1732bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1733bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1734bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1735bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View findAttachmentView(long attachmentId) { 1736bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook for (int i = 0, count = mAttachments.getChildCount(); i < count; i++) { 1737bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook View view = mAttachments.getChildAt(i); 1738bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageViewAttachmentInfo attachment = (MessageViewAttachmentInfo) view.getTag(); 1739bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachment.mId == attachmentId) { 1740bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return view; 1741bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1742bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1743bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return null; 1744bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1745bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1746bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MessageViewAttachmentInfo findAttachmentInfo(long attachmentId) { 1747bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook View view = findAttachmentView(attachmentId); 1748bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (view != null) { 1749bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return (MessageViewAttachmentInfo)view.getTag(); 1750bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1751bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return null; 1752bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1753bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1754bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1755bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Controller results listener. We wrap it with {@link ControllerResultUiThreadWrapper}, 1756bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * so all methods are called on the UI thread. 1757bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1758bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class ControllerResults extends Controller.Result { 1759bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private long mWaitForLoadMessageId; 1760bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1761bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void setWaitForLoadMessageId(long messageId) { 1762bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mWaitForLoadMessageId = messageId; 1763bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1764bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1765bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1766bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void loadMessageForViewCallback(MessagingException result, long accountId, 1767bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook long messageId, int progress) { 1768bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (messageId != mWaitForLoadMessageId) { 1769bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // We are not waiting for this message to load, so exit quickly 1770bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1771bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1772bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (result == null) { 1773bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (progress) { 1774bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case 0: 1775bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onLoadMessageStarted(); 1776bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Loading from network -- show the progress icon. 1777bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showContent(false, true); 1778bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1779bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case 100: 1780bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mWaitForLoadMessageId = -1; 1781bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onLoadMessageFinished(); 1782bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // reload UI and reload everything else too 1783bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // pass false to LoadMessageTask to prevent looping here 1784bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cancelAllTasks(); 1785bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new LoadMessageTask(false).executeParallel(); 1786bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1787bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook default: 1788bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // do nothing - we don't have a progress bar at this time 1789bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1790bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1791bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1792bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mWaitForLoadMessageId = Message.NO_MESSAGE; 1793bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String error = mContext.getString(R.string.status_network_error); 1794bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onLoadMessageError(error); 1795bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook resetView(); 1796bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1797bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1798bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1799bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1800bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void loadAttachmentCallback(MessagingException result, long accountId, 1801bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook long messageId, long attachmentId, int progress) { 1802bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (messageId == mMessageId) { 1803bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (result == null) { 1804bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showAttachmentProgress(attachmentId, progress); 1805bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (progress) { 1806bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case 100: 1807bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final MessageViewAttachmentInfo attachmentInfo = 1808bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook findAttachmentInfoFromView(attachmentId); 1809bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachmentInfo != null) { 1810bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updatePreviewIcon(attachmentInfo); 1811bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1812bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook doFinishLoadAttachment(attachmentId); 1813bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1814bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook default: 1815bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // do nothing - we don't have a progress bar at this time 1816bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1817bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1818bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1819bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageViewAttachmentInfo attachment = findAttachmentInfo(attachmentId); 1820bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachment == null) { 1821bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Called before LoadAttachmentsTask finishes. 1822bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // (Possible if you quickly close & re-open a message) 1823bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1824bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1825bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.cancelButton.setVisibility(View.GONE); 1826bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.loadButton.setVisibility(View.VISIBLE); 1827bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.hideProgress(); 1828bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1829bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final String error; 1830bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (result.getCause() instanceof IOException) { 1831bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook error = mContext.getString(R.string.status_network_error); 1832bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1833bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook error = mContext.getString( 1834bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook R.string.message_view_load_attachment_failed_toast, 1835bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.mName); 1836bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1837bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onLoadMessageError(error); 1838bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1839bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1840bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1841bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1842bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void showAttachmentProgress(long attachmentId, int progress) { 1843bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageViewAttachmentInfo attachment = findAttachmentInfo(attachmentId); 1844bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (attachment != null) { 1845bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (progress == 0) { 1846bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.cancelButton.setVisibility(View.GONE); 1847bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1848bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook attachment.showProgress(progress); 1849bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1850bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1851bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1852bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1853bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1854bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Class to detect update on the current message (e.g. toggle star). When it gets content 1855bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * change notifications, it kicks {@link ReloadMessageTask}. 1856bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1857bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class MessageObserver extends ContentObserver implements Runnable { 1858bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final Throttle mThrottle; 1859bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final ContentResolver mContentResolver; 1860bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1861bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mRegistered; 1862bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1863bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public MessageObserver(Handler handler, Context context) { 1864bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(handler); 1865bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContentResolver = context.getContentResolver(); 1866bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mThrottle = new Throttle("MessageObserver", this, handler); 1867bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1868bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1869bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void unregister() { 1870bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!mRegistered) { 1871bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1872bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1873bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mThrottle.cancelScheduledCallback(); 1874bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContentResolver.unregisterContentObserver(this); 1875bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRegistered = false; 1876bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1877bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1878bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void register(Uri notifyUri) { 1879bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook unregister(); 1880bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContentResolver.registerContentObserver(notifyUri, true, this); 1881bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRegistered = true; 1882bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1883bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1884bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1885bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean deliverSelfNotifications() { 1886bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return true; 1887bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1888bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1889bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1890bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onChange(boolean selfChange) { 1891bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mRegistered) { 1892bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mThrottle.onEvent(); 1893bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1894bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1895bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1896bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** This method is delay-called by {@link Throttle} on the UI thread. */ 1897bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1898bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void run() { 1899bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // This method is delay-called, so need to make sure if it's still registered. 1900bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mRegistered) { 1901bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new ReloadMessageTask().cancelPreviousAndExecuteParallel(); 1902bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1903bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1904bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1905bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1906bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void updatePreviewIcon(MessageViewAttachmentInfo attachmentInfo) { 1907bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new UpdatePreviewIconTask(attachmentInfo).executeParallel(); 1908bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1909bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1910bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class UpdatePreviewIconTask extends EmailAsyncTask<Void, Void, Bitmap> { 1911bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @SuppressWarnings("hiding") 1912bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final Context mContext; 1913bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final MessageViewAttachmentInfo mAttachmentInfo; 1914bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1915bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public UpdatePreviewIconTask(MessageViewAttachmentInfo attachmentInfo) { 1916bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(mTaskTracker); 1917bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mContext = getActivity(); 1918bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachmentInfo = attachmentInfo; 1919bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1920bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1921bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1922bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected Bitmap doInBackground(Void... params) { 1923bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return getPreviewIcon(mContext, mAttachmentInfo); 1924bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1925bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1926bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1927bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void onSuccess(Bitmap result) { 1928bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (result == null) { 1929bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1930bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1931bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAttachmentInfo.iconView.setImageBitmap(result); 1932bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1933bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1934bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1935bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean shouldShowImagesFor(String senderEmail) { 1936bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return Preferences.getPreferences(getActivity()).shouldShowImagesFor(senderEmail); 1937bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1938bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1939bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void setShowImagesForSender() { 1940bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook makeVisible(UiUtilities.getView(getView(), R.id.always_show_pictures_button), false); 1941bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.showToast(getActivity(), R.string.message_view_always_show_pictures_confirmation); 1942bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1943bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Force redraw of the container. 1944bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateTabs(mTabFlags); 1945bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1946bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Address[] fromList = Address.unpack(mMessage.mFrom); 1947bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Preferences prefs = Preferences.getPreferences(getActivity()); 1948bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook for (Address sender : fromList) { 1949bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String email = sender.getAddress(); 1950bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook prefs.setSenderAsTrusted(email); 1951bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1952bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1953bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1954bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean isMessageLoadedForTest() { 1955bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mIsMessageLoadedForTest; 1956bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1957bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1958bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void clearIsMessageLoadedForTest() { 1959bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mIsMessageLoadedForTest = true; 1960bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1961bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook} 1962