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.ListFragment; 21bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.app.LoaderManager; 22bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.ClipData; 23bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.ContentUris; 24bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.Context; 25bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.Loader; 26bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.res.Configuration; 27bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.content.res.Resources; 28bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.database.Cursor; 29bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.graphics.Canvas; 30bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.graphics.Point; 31bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.graphics.PointF; 32bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.graphics.Rect; 33bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.graphics.Typeface; 34bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.graphics.drawable.Drawable; 35bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.os.Bundle; 36bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.os.Parcelable; 37bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.text.TextPaint; 38bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.util.Log; 39bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.ActionMode; 40bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.DragEvent; 41bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.LayoutInflater; 42bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.Menu; 43bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.MenuInflater; 44bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.MenuItem; 45bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.MotionEvent; 46bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.View; 47bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.View.DragShadowBuilder; 48bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.View.OnDragListener; 49bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.View.OnTouchListener; 50bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.view.ViewGroup; 51bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.AdapterView; 52bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.AdapterView.OnItemLongClickListener; 53bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.ListView; 54bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.TextView; 55bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport android.widget.Toast; 56bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 57bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.Controller; 58bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.Email; 59bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.MessageListContext; 60bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.NotificationController; 61bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.R; 62bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.RefreshManager; 63bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.activity.MessagesAdapter.SearchResultsCursor; 64bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.email.provider.EmailProvider; 65bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.Logging; 66bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.provider.Account; 67bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.provider.EmailContent.Message; 68bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.provider.Mailbox; 69bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.utility.EmailAsyncTask; 70bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.android.emailcommon.utility.Utility; 71bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport com.google.common.annotations.VisibleForTesting; 72bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 73bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.util.HashMap; 74bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookimport java.util.Set; 75bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 76bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook/** 77bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Message list. 78bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 79bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * See the class javadoc for {@link MailboxListFragment} for notes on {@link #getListView()} and 80bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * {@link #isViewCreated()}. 81bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 82bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrookpublic class MessageListFragment extends ListFragment 83bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook implements OnItemLongClickListener, MessagesAdapter.Callback, 84bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MoveMessageToDialog.Callback, OnDragListener, OnTouchListener { 85bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final String BUNDLE_LIST_STATE = "MessageListFragment.state.listState"; 86bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final String BUNDLE_KEY_SELECTED_MESSAGE_ID 87bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook = "messageListFragment.state.listState.selected_message_id"; 88bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 89bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final int LOADER_ID_MESSAGES_LOADER = 1; 90bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 91bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Argument name(s) */ 92bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final String ARG_LIST_CONTEXT = "listContext"; 93bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 94bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Controller access 95bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Controller mController; 96bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private RefreshManager mRefreshManager; 97bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final RefreshListener mRefreshListener = new RefreshListener(); 98bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 99bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // UI Support 100bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Activity mActivity; 101bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Callback mCallback = EmptyCallback.INSTANCE; 102bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mIsViewCreated; 103bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 104bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mListPanel; 105bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mListFooterView; 106bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mListFooterText; 107bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private View mListFooterProgress; 108bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private ViewGroup mSearchHeader; 109bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private ViewGroup mWarningContainer; 110bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mSearchHeaderText; 111bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private TextView mSearchHeaderCount; 112bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 113bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final int LIST_FOOTER_MODE_NONE = 0; 114bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final int LIST_FOOTER_MODE_MORE = 1; 115bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int mListFooterMode; 116bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 117bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MessagesAdapter mListAdapter; 118bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mIsFirstLoad; 119bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 120bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** ID of the message to hightlight. */ 121bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private long mSelectedMessageId = -1; 122bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 123bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Account mAccount; 124bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Mailbox mMailbox; 125bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** The original mailbox being searched, if this list is showing search results. */ 126bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Mailbox mSearchedMailbox; 127bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mIsEasAccount; 128bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mIsRefreshable; 129bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int mCountTotalAccounts; 130bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 131bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Misc members 132bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 133bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mShowSendCommand; 134bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mShowMoveCommand; 135bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 136bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 137bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * If true, we disable the CAB even if there are selected messages. 138bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * It's used in portrait on the tablet when the message view becomes visible and the message 139bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * list gets pushed out of the screen, in which case we want to keep the selection but the CAB 140bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * should be gone. 141bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 142bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mDisableCab; 143bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 144bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** true between {@link #onResume} and {@link #onPause}. */ 145bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean mResumed; 146bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 147bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 148bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * {@link ActionMode} shown when 1 or more message is selected. 149bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 150bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private ActionMode mSelectionMode; 151bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private SelectionModeCallback mLastSelectionModeCallback; 152bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 153bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private Parcelable mSavedListState; 154bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 155bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker(); 156bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 157bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 158bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Callback interface that owning activities must implement 159bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 160bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public interface Callback { 161bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public static final int TYPE_REGULAR = 0; 162bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public static final int TYPE_DRAFT = 1; 163bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public static final int TYPE_TRASH = 2; 164bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 165bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 166bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when the specified mailbox does not exist. 167bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 168bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onMailboxNotFound(boolean firstLoad); 169bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 170bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 171bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when the user wants to open a message. 172bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Note {@code mailboxId} is of the actual mailbox of the message, which is different from 173bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * {@link MessageListFragment#getMailboxId} if it's magic mailboxes. 174bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 175bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param messageId the message ID of the message 176bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param messageMailboxId the mailbox ID of the message. 177bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * This will never take values like {@link Mailbox#QUERY_ALL_INBOXES}. 178bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param listMailboxId the mailbox ID of the listbox shown on this fragment. 179bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * This can be that of a magic mailbox, e.g. {@link Mailbox#QUERY_ALL_INBOXES}. 180bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param type {@link #TYPE_REGULAR}, {@link #TYPE_DRAFT} or {@link #TYPE_TRASH}. 181bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 182bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onMessageOpen(long messageId, long messageMailboxId, long listMailboxId, 183bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int type); 184bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 185bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 186bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when an operation is initiated that can potentially advance the current 187bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * message selection (e.g. a delete operation may advance the selection). 188bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param affectedMessages the messages the operation will apply to 189bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 190bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onAdvancingOpAccepted(Set<Long> affectedMessages); 191bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 192bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 193bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when a drag & drop is initiated. 194bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 195bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true if drag & drop is allowed 196bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 197bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onDragStarted(); 198bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 199bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 200bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when a drag & drop is ended. 201bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 202bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDragEnded(); 203bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 204bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 205bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static final class EmptyCallback implements Callback { 206bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public static final Callback INSTANCE = new EmptyCallback(); 207bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 208bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 209bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onMailboxNotFound(boolean isFirstLoad) { 210bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 211bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 212bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 213bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onMessageOpen( 214bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook long messageId, long messageMailboxId, long listMailboxId, int type) { 215bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 216bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 217bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 218bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onAdvancingOpAccepted(Set<Long> affectedMessages) { 219bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 220bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 221bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 222bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onDragStarted() { 223bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; // We don't know -- err on the safe side. 224bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 225bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 226bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 227bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDragEnded() { 228bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 229bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 230bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 231bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 232bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Create a new instance with initialization parameters. 233bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 234bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * This fragment should be created only with this method. (Arguments should always be set.) 235bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 236bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param listContext The list context to show messages for 237bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 238bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public static MessageListFragment newInstance(MessageListContext listContext) { 239bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final MessageListFragment instance = new MessageListFragment(); 240bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final Bundle args = new Bundle(); 241bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook args.putParcelable(ARG_LIST_CONTEXT, listContext); 242bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook instance.setArguments(args); 243bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return instance; 244bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 245bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 246bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 247bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * The context describing the contents to be shown in the list. 248bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Do not use directly; instead, use the getters such as {@link #getAccountId()}. 249bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * <p><em>NOTE:</em> Although we cannot force these to be immutable using Java language 250bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * constructs, this <em>must</em> be considered immutable. 251bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 252bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MessageListContext mListContext; 253bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 254bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void initializeArgCache() { 255bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mListContext != null) return; 256bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListContext = getArguments().getParcelable(ARG_LIST_CONTEXT); 257bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 258bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 259bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 260bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return the account ID passed to {@link #newInstance}. Safe to call even before onCreate. 261bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 262bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * NOTE it may return {@link Account#ACCOUNT_ID_COMBINED_VIEW}. 263bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 264bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public long getAccountId() { 265bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook initializeArgCache(); 266bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mListContext.mAccountId; 267bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 268bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 269bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 270bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return the mailbox ID passed to {@link #newInstance}. Safe to call even before onCreate. 271bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 272bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public long getMailboxId() { 273bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook initializeArgCache(); 274bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mListContext.getMailboxId(); 275bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 276bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 277bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 278bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true if the mailbox is a combined mailbox. Safe to call even before onCreate. 279bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 280bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean isCombinedMailbox() { 281bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return getAccountId() == Account.ACCOUNT_ID_COMBINED_VIEW; 282bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 283bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 284bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public MessageListContext getListContext() { 285bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook initializeArgCache(); 286bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mListContext; 287bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 288bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 289bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 290bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return Whether or not initial data is loaded in this list. 291bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 292bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean hasDataLoaded() { 293bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mCountTotalAccounts > 0; 294bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 295bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 296bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 297bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return The account object, when known. Null if not yet known. 298bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 299bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public Account getAccount() { 300bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mAccount; 301bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 302bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 303bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 304bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return The mailbox where the messages belong in, when known. Null if not yet known. 305bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 306bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public Mailbox getMailbox() { 307bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mMailbox; 308bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 309bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 310bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 311bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return Whether or not this message list is showing a user's inbox. 312bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Note that combined inbox view is treated as an inbox view. 313bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 314bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean isInboxList() { 315bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageListContext listContext = getListContext(); 316bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook long accountId = listContext.mAccountId; 317bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (accountId == Account.ACCOUNT_ID_COMBINED_VIEW) { 318bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return listContext.getMailboxId() == Mailbox.QUERY_ALL_INBOXES; 319bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 320bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 321bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!hasDataLoaded()) { 322bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // If the data hasn't finished loading, we don't have the full mailbox - infer from ID. 323bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook long inboxId = Mailbox.findMailboxOfType(mActivity, accountId, Mailbox.TYPE_INBOX); 324bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return listContext.getMailboxId() == inboxId; 325bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 326bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return (mMailbox != null) && (mMailbox.mType == Mailbox.TYPE_INBOX); 327bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 328bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 329bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 330bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return The mailbox being searched, when known. Null if not yet known or if not a search 331bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * result. 332bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 333bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public Mailbox getSearchedMailbox() { 334bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mSearchedMailbox; 335bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 336bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 337bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 338bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onAttach(Activity activity) { 339bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 340bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onAttach"); 341bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 342bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onAttach(activity); 343bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 344bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 345bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 346bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onCreate(Bundle savedInstanceState) { 347bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 348bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onCreate"); 349bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 350bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onCreate(savedInstanceState); 351bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 352bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mActivity = getActivity(); 353bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setHasOptionsMenu(true); 354bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController = Controller.getInstance(mActivity); 355bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRefreshManager = RefreshManager.getInstance(mActivity); 356bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 357bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter = new MessagesAdapter(mActivity, this, getListContext().isSearch()); 358bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mIsFirstLoad = true; 359bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 360bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 361bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 362bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public View onCreateView( 363bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 364bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 365bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onCreateView"); 366bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 367bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Use a custom layout, which includes the original layout with "send messages" panel. 368bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook View root = inflater.inflate(R.layout.message_list_fragment,null); 369bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mIsViewCreated = true; 370bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListPanel = UiUtilities.getView(root, R.id.list_panel); 371bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return root; 372bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 373bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 374bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void setLayout(ThreePaneLayout layout) { 375bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (UiUtilities.useTwoPane(mActivity)) { 376bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.setLayout(layout); 377bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 378bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 379bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 380bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void initSearchHeader() { 381bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mSearchHeader == null) { 382bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ViewGroup root = (ViewGroup) getView(); 383bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSearchHeader = (ViewGroup) LayoutInflater.from(mActivity).inflate( 384bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook R.layout.message_list_search_header, root, false); 385bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSearchHeaderText = UiUtilities.getView(mSearchHeader, R.id.search_header_text); 386bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSearchHeaderCount = UiUtilities.getView(mSearchHeader, R.id.search_count); 387bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 388bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Add above the actual list. 389bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook root.addView(mSearchHeader, 0); 390bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 391bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 392bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 393bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 394bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true if the content view is created and not destroyed yet. (i.e. between 395bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * {@link #onCreateView} and {@link #onDestroyView}. 396bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 397bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean isViewCreated() { 398bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Note that we don't use "getView() != null". This method is used in updateSelectionMode() 399bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // to determine if CAB shold be shown. But because it's called from onDestroyView(), at 400bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // this point the fragment still has views but we want to hide CAB, we can't use 401bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // getView() here. 402bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mIsViewCreated; 403bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 404bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 405bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 406bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onActivityCreated(Bundle savedInstanceState) { 407bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 408bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onActivityCreated"); 409bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 410bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onActivityCreated(savedInstanceState); 411bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 412bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final ListView lv = getListView(); 413bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lv.setOnItemLongClickListener(this); 414bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lv.setOnTouchListener(this); 415bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lv.setItemsCanFocus(false); 416bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 417bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 418bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListFooterView = getActivity().getLayoutInflater().inflate( 419bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook R.layout.message_list_item_footer, lv, false); 420bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setEmptyText(getString(R.string.message_list_no_messages)); 421bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 422bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (savedInstanceState != null) { 423bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Fragment doesn't have this method. Call it manually. 424bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook restoreInstanceState(savedInstanceState); 425bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 426bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 427bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook startLoading(); 428bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 429bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook UiUtilities.installFragment(this); 430bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 431bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 432bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 433bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onStart() { 434bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 435bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onStart"); 436bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 437bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onStart(); 438bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 439bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 440bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 441bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onResume() { 442bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 443bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onResume"); 444bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 445bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onResume(); 446bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook adjustMessageNotification(false); 447bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRefreshManager.registerListener(mRefreshListener); 448bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mResumed = true; 449bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 450bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 451bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 452bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onPause() { 453bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 454bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onPause"); 455bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 456bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mResumed = false; 457bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSavedListState = getListView().onSaveInstanceState(); 458bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook adjustMessageNotification(true); 459bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onPause(); 460bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 461bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 462bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 463bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onStop() { 464bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 465bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onStop"); 466bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 467bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mTaskTracker.cancellAllInterrupt(); 468bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRefreshManager.unregisterListener(mRefreshListener); 469bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 470bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onStop(); 471bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 472bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 473bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 474bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDestroyView() { 475bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 476bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onDestroyView"); 477bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 478bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mIsViewCreated = false; // Clear this first for updateSelectionMode(). See isViewCreated(). 479bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook UiUtilities.uninstallFragment(this); 480bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateSelectionMode(); 481bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 482bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Reset the footer mode since we just blew away the footer view we were holding on to. 483bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // This will get re-updated when/if this fragment is restored. 484bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListFooterMode = LIST_FOOTER_MODE_NONE; 485bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onDestroyView(); 486bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 487bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 488bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 489bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDestroy() { 490bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 491bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onDestroy"); 492bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 493bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 494bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook finishSelectionMode(); 495bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onDestroy(); 496bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 497bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 498bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 499bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDetach() { 500bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 501bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onDetach"); 502bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 503bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onDetach(); 504bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 505bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 506bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 507bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onSaveInstanceState(Bundle outState) { 508bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 509bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " onSaveInstanceState"); 510bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 511bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onSaveInstanceState(outState); 512bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.onSaveInstanceState(outState); 513bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (isViewCreated()) { 514bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook outState.putParcelable(BUNDLE_LIST_STATE, getListView().onSaveInstanceState()); 515bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 516bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook outState.putLong(BUNDLE_KEY_SELECTED_MESSAGE_ID, mSelectedMessageId); 517bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 518bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 519bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @VisibleForTesting 520bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook void restoreInstanceState(Bundle savedInstanceState) { 521bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 522bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " restoreInstanceState"); 523bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 524bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.loadState(savedInstanceState); 525bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSavedListState = savedInstanceState.getParcelable(BUNDLE_LIST_STATE); 526bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSelectedMessageId = savedInstanceState.getLong(BUNDLE_KEY_SELECTED_MESSAGE_ID); 527bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 528bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 529bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 530bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onPrepareOptionsMenu(Menu menu) { 531bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MenuItem send = menu.findItem(R.id.send); 532bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (send != null) { 533bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook send.setVisible(mShowSendCommand); 534bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 535bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 536bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 537bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 538bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onOptionsItemSelected(MenuItem item) { 539bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (item.getItemId()) { 540bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.send: 541bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onSendPendingMessages(); 542bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return true; 543bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 544bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 545bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 546bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 547bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 548bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void setCallback(Callback callback) { 549bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback = (callback != null) ? callback : EmptyCallback.INSTANCE; 550bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 551bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 552bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 553bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * This method must be called when the fragment is hidden/shown. 554bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 555bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onHidden(boolean hidden) { 556bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // When hidden, we need to disable CAB. 557bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (hidden == mDisableCab) { 558bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 559bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 560bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDisableCab = hidden; 561bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateSelectionMode(); 562bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 563bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 564bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void setSelectedMessage(long messageId) { 565bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mSelectedMessageId == messageId) { 566bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 567bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 568bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSelectedMessageId = messageId; 569bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mResumed) { 570bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook highlightSelectedMessage(true); 571bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 572bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 573bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 574bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 575bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true if the mailbox is refreshable. false otherwise, or unknown yet. 576bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 577bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean isRefreshable() { 578bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mIsRefreshable; 579bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 580bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 581bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 582bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return the number of messages that are currently selected. 583bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 584bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int getSelectedCount() { 585bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mListAdapter.getSelectedSet().size(); 586bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 587bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 588bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 589bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true if the list is in the "selection" mode. 590bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 591bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean isInSelectionMode() { 592bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return mSelectionMode != null; 593bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 594bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 595bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 596bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when a message is clicked. 597bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 598bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 599bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onListItemClick(ListView parent, View view, int position, long id) { 600bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (view != mListFooterView) { 601bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageListItem itemView = (MessageListItem) view; 602bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onMessageOpen(itemView.mMailboxId, id); 603bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 604bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook doFooterClick(); 605bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 606bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 607bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 608bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // This is tentative drag & drop UI 609bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static class ShadowBuilder extends DragShadowBuilder { 610bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static Drawable sBackground; 611bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Paint information for the move message text */ 612bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static TextPaint sMessagePaint; 613bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Paint information for the message count */ 614bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static TextPaint sCountPaint; 615bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** The x location of any touch event; used to ensure the drag overlay is drawn correctly */ 616bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static int sTouchX; 617bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 618bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Width of the draggable view */ 619bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final int mDragWidth; 620bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Height of the draggable view */ 621bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final int mDragHeight; 622bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 623bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final String mMessageText; 624bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final PointF mMessagePoint; 625bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 626bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final String mCountText; 627bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final PointF mCountPoint; 628bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int mOldOrientation = Configuration.ORIENTATION_UNDEFINED; 629bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 630bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Margin applied to the right of count text */ 631bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static float sCountMargin; 632bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Margin applied to left of the message text */ 633bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static float sMessageMargin; 634bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Vertical offset of the drag view */ 635bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private static int sDragOffset; 636bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 637bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public ShadowBuilder(View view, int count) { 638bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(view); 639bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Resources res = view.getResources(); 640bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int newOrientation = res.getConfiguration().orientation; 641bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 642bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDragHeight = view.getHeight(); 643bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mDragWidth = view.getWidth(); 644bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 645bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // TODO: Can we define a layout for the contents of the drag area? 646bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (sBackground == null || mOldOrientation != newOrientation) { 647bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mOldOrientation = newOrientation; 648bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 649bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sBackground = res.getDrawable(R.drawable.list_pressed_holo); 650bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sBackground.setBounds(0, 0, mDragWidth, mDragHeight); 651bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 652bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sDragOffset = (int)res.getDimension(R.dimen.message_list_drag_offset); 653bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 654bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sMessagePaint = new TextPaint(); 655bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook float messageTextSize; 656bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook messageTextSize = res.getDimension(R.dimen.message_list_drag_message_font_size); 657bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sMessagePaint.setTextSize(messageTextSize); 658bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sMessagePaint.setTypeface(Typeface.DEFAULT_BOLD); 659bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sMessagePaint.setAntiAlias(true); 660bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sMessageMargin = res.getDimension(R.dimen.message_list_drag_message_right_margin); 661bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 662bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sCountPaint = new TextPaint(); 663bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook float countTextSize; 664bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook countTextSize = res.getDimension(R.dimen.message_list_drag_count_font_size); 665bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sCountPaint.setTextSize(countTextSize); 666bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sCountPaint.setTypeface(Typeface.DEFAULT_BOLD); 667bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sCountPaint.setAntiAlias(true); 668bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sCountMargin = res.getDimension(R.dimen.message_list_drag_count_left_margin); 669bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 670bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 671bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Calculate layout positions 672bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Rect b = new Rect(); 673bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 674bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageText = res.getQuantityString(R.plurals.move_messages, count, count); 675bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sMessagePaint.getTextBounds(mMessageText, 0, mMessageText.length(), b); 676bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessagePoint = new PointF(mDragWidth - b.right - sMessageMargin, 677bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook (mDragHeight - b.top)/ 2); 678bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 679bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCountText = Integer.toString(count); 680bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sCountPaint.getTextBounds(mCountText, 0, mCountText.length(), b); 681bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCountPoint = new PointF(sCountMargin, 682bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook (mDragHeight - b.top) / 2); 683bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 684bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 685bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 686bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) { 687bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook shadowSize.set(mDragWidth, mDragHeight); 688bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook shadowTouchPoint.set(sTouchX, (mDragHeight / 2) + sDragOffset); 689bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 690bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 691bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 692bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDrawShadow(Canvas canvas) { 693bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super.onDrawShadow(canvas); 694bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook sBackground.draw(canvas); 695bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook canvas.drawText(mMessageText, mMessagePoint.x, mMessagePoint.y, sMessagePaint); 696bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook canvas.drawText(mCountText, mCountPoint.x, mCountPoint.y, sCountPaint); 697bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 698bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 699bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 700bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 701bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onDrag(View view, DragEvent event) { 702bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch(event.getAction()) { 703bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case DragEvent.ACTION_DRAG_ENDED: 704bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (event.getResult()) { 705bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onDeselectAll(); // Clear the selection 706bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 707bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onDragEnded(); 708bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 709bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 710bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 711bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 712bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 713bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 714bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onTouch(View v, MotionEvent event) { 715bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (event.getAction() == MotionEvent.ACTION_DOWN) { 716bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Save the touch location to draw the drag overlay at the correct location 717bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ShadowBuilder.sTouchX = (int)event.getX(); 718bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 719bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // don't do anything, let the system process the event 720bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 721bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 722bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 723bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 724bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { 725bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (view != mListFooterView) { 726bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Always toggle the item. 727bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageListItem listItem = (MessageListItem) view; 728bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean toggled = false; 729bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!mListAdapter.isSelected(listItem)) { 730bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook toggleSelection(listItem); 731bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook toggled = true; 732bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 733bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 734bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Additionally, check to see if we can drag the item. 735bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!mCallback.onDragStarted()) { 736bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return toggled; // D&D not allowed. 737bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 738bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // We can't move from combined accounts view 739bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // We also need to check the actual mailbox to see if we can move items from it 740bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final long mailboxId = getMailboxId(); 741bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mAccount == null || mMailbox == null) { 742bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 743bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else if (mailboxId > 0 && !mMailbox.canHaveMessagesMoved()) { 744bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 745bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 746bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Start drag&drop. 747bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 748bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Create ClipData with the Uri of the message we're long clicking 749bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ClipData data = ClipData.newUri(mActivity.getContentResolver(), 750bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageListItem.MESSAGE_LIST_ITEMS_CLIP_LABEL, Message.CONTENT_URI.buildUpon() 751bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook .appendPath(Long.toString(listItem.mMessageId)) 752bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook .appendQueryParameter( 753bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook EmailProvider.MESSAGE_URI_PARAMETER_MAILBOX_ID, 754bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Long.toString(mailboxId)) 755bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook .build()); 756bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Set<Long> selectedMessageIds = mListAdapter.getSelectedSet(); 757bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int size = selectedMessageIds.size(); 758bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Add additional Uri's for any other selected messages 759bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook for (Long messageId: selectedMessageIds) { 760bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (messageId.longValue() != listItem.mMessageId) { 761bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook data.addItem(new ClipData.Item( 762bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ContentUris.withAppendedId(Message.CONTENT_URI, messageId))); 763bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 764bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 765bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Start dragging now 766bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook listItem.setOnDragListener(this); 767bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook listItem.startDrag(data, new ShadowBuilder(listItem, size), null, 0); 768bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return true; 769bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 770bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 771bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 772bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 773bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void toggleSelection(MessageListItem itemView) { 774bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook itemView.invalidate(); 775bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.toggleSelected(itemView); 776bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 777bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 778bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 779bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Called when a message on the list is selected 780bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 781bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param messageMailboxId the actual mailbox ID of the message. Note it's different than 782bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * what is returned by {@link #getMailboxId()} for combined mailboxes. 783bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * ({@link #getMailboxId()} may return special mailbox values such as 784bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * {@link Mailbox#QUERY_ALL_INBOXES}) 785bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param messageId ID of the message to open. 786bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 787bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onMessageOpen(final long messageMailboxId, final long messageId) { 788bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if ((mMailbox != null) && (mMailbox.mId == messageMailboxId)) { 789bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Normal case - the message belongs in the mailbox list we're viewing. 790bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onMessageOpen(messageId, messageMailboxId, 791bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook getMailboxId(), callbackTypeForMailboxType(mMailbox.mType)); 792bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 793bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 794bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 795bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Weird case - a virtual mailbox where the messages could come from different mailbox 796bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // types - here we have to query the DB for the type. 797bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new MessageOpenTask(messageMailboxId, messageId).cancelPreviousAndExecuteParallel(); 798bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 799bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 800bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int callbackTypeForMailboxType(int mailboxType) { 801bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (mailboxType) { 802bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case Mailbox.TYPE_DRAFTS: 803bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return Callback.TYPE_DRAFT; 804bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case Mailbox.TYPE_TRASH: 805bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return Callback.TYPE_TRASH; 806bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook default: 807bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return Callback.TYPE_REGULAR; 808bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 809bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 810bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 811bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 812bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Task to look up the mailbox type for a message, and kicks the callback. 813bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 814bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class MessageOpenTask extends EmailAsyncTask<Void, Void, Integer> { 815bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final long mMessageMailboxId; 816bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final long mMessageId; 817bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 818bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public MessageOpenTask(long messageMailboxId, long messageId) { 819bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook super(mTaskTracker); 820bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageMailboxId = messageMailboxId; 821bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMessageId = messageId; 822bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 823bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 824bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 825bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected Integer doInBackground(Void... params) { 826bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Restore the mailbox type. Note we can't use mMailbox.mType here, because 827bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // we don't have mMailbox for combined mailbox. 828bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // ("All Starred" can contain any kind of messages.) 829bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return callbackTypeForMailboxType( 830bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Mailbox.getMailboxType(mActivity, mMessageMailboxId)); 831bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 832bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 833bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 834bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook protected void onSuccess(Integer type) { 835bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (type == null) { 836bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 837bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 838bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onMessageOpen(mMessageId, mMessageMailboxId, getMailboxId(), type); 839bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 840bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 841bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 842bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void showMoveMessagesDialog(Set<Long> selectedSet) { 843bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook long[] messageIds = Utility.toPrimitiveLongArray(selectedSet); 844bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MoveMessageToDialog dialog = MoveMessageToDialog.newInstance(messageIds, this); 845bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook dialog.show(getFragmentManager(), "dialog"); 846bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 847bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 848bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 849bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onMoveToMailboxSelected(long newMailboxId, long[] messageIds) { 850bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final Context context = getActivity(); 851bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (context == null) { 852bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Detached from activity. This callback was really delayed or a monkey was involved. 853bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 854bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 855bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 856bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onAdvancingOpAccepted(Utility.toLongSet(messageIds)); 857bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ActivityHelper.moveMessages(context, newMailboxId, messageIds); 858bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 859bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Move is async, so we can't refresh now. Instead, just clear the selection. 860bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onDeselectAll(); 861bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 862bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 863bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 864bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Refresh the list. NOOP for special mailboxes (e.g. combined inbox). 865bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 866bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Note: Manual refresh is enabled even for push accounts. 867bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 868bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onRefresh(boolean userRequest) { 869bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mIsRefreshable) { 870bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRefreshManager.refreshMessageList(getAccountId(), getMailboxId(), userRequest); 871bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 872bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 873bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 874bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onDeselectAll() { 875bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.clearSelection(); 876bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (isInSelectionMode()) { 877bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook finishSelectionMode(); 878bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 879bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 880bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 881bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 882bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Load more messages. NOOP for special mailboxes (e.g. combined inbox). 883bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 884bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onLoadMoreMessages() { 885bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mIsRefreshable) { 886bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRefreshManager.loadMoreMessages(getAccountId(), getMailboxId()); 887bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 888bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 889bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 890bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onSendPendingMessages() { 891bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook RefreshManager rm = RefreshManager.getInstance(mActivity); 892bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (getMailboxId() == Mailbox.QUERY_ALL_OUTBOX) { 893bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook rm.sendPendingMessagesForAllAccounts(); 894bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else if (mMailbox != null) { // Magic boxes don't have a specific account id. 895bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook rm.sendPendingMessages(mMailbox.mAccountKey); 896bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 897bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 898bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 899bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 900bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Toggles a set read/unread states. Note, the default behavior is "mark unread", so the 901bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * sense of the helper methods is "true=unread"; this may be called from the UI thread 902bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 903bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param selectedSet The current list of selected items 904bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 905bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void toggleRead(Set<Long> selectedSet) { 906bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook toggleMultiple(selectedSet, new MultiToggleHelper() { 907bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 908bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 909bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean getField(Cursor c) { 910bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return c.getInt(MessagesAdapter.COLUMN_READ) == 0; 911bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 912bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 913bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 914bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void setField(long messageId, boolean newValue) { 915bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController.setMessageReadSync(messageId, !newValue); 916bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 917bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook }); 918bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 919bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 920bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 921bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Toggles a set of favorites (stars); this may be called from the UI thread 922bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 923bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param selectedSet The current list of selected items 924bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 925bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void toggleFavorite(Set<Long> selectedSet) { 926bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook toggleMultiple(selectedSet, new MultiToggleHelper() { 927bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 928bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 929bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean getField(Cursor c) { 930bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return c.getInt(MessagesAdapter.COLUMN_FAVORITE) != 0; 931bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 932bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 933bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 934bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void setField(long messageId, boolean newValue) { 935bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController.setMessageFavoriteSync(messageId, newValue); 936bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 937bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook }); 938bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 939bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 940bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void deleteMessages(Set<Long> selectedSet) { 941bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final long[] messageIds = Utility.toPrimitiveLongArray(selectedSet); 942bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController.deleteMessages(messageIds); 943bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Toast.makeText(mActivity, mActivity.getResources().getQuantityString( 944bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook R.plurals.message_deleted_toast, messageIds.length), Toast.LENGTH_SHORT).show(); 945bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook selectedSet.clear(); 946bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Message deletion is async... Can't refresh the list immediately. 947bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 948bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 949bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private interface MultiToggleHelper { 950bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 951bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Return true if the field of interest is "set". If one or more are false, then our 952bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * bulk action will be to "set". If all are set, our bulk action will be to "clear". 953bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param c the cursor, positioned to the item of interest 954bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true if the field at this row is "set" 955bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 956bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean getField(Cursor c); 957bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 958bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 959bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Set or clear the field of interest; setField is called asynchronously via EmailAsyncTask 960bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param messageId the message id of the current message 961bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param newValue the new value to be set at this row 962bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 963bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void setField(long messageId, boolean newValue); 964bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 965bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 966bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 967bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Toggle multiple fields in a message, using the following logic: If one or more fields 968bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * are "clear", then "set" them. If all fields are "set", then "clear" them all. Provider 969bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * calls are applied asynchronously in setField 970bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 971bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param selectedSet the set of messages that are selected 972bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param helper functions to implement the specific getter & setter 973bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 974bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void toggleMultiple(final Set<Long> selectedSet, final MultiToggleHelper helper) { 975bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final Cursor c = mListAdapter.getCursor(); 976bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (c == null || c.isClosed()) { 977bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 978bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 979bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 980bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final HashMap<Long, Boolean> setValues = new HashMap<Long, Boolean>(); 981bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean allWereSet = true; 982bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 983bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook c.moveToPosition(-1); 984bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook while (c.moveToNext()) { 985bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook long id = c.getInt(MessagesAdapter.COLUMN_ID); 986bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (selectedSet.contains(id)) { 987bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean value = helper.getField(c); 988bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setValues.put(id, value); 989bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook allWereSet = allWereSet && value; 990bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 991bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 992bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 993bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!setValues.isEmpty()) { 994bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final boolean newValue = !allWereSet; 995bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook c.moveToPosition(-1); 996bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // TODO: we should probably put up a dialog or some other progress indicator for this. 997bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook EmailAsyncTask.runAsyncParallel(new Runnable() { 998bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 999bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void run() { 1000bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook for (long id : setValues.keySet()) { 1001bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (setValues.get(id) != newValue) { 1002bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook helper.setField(id, newValue); 1003bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1004bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1005bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook }}); 1006bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1007bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1008bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1009bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1010bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Test selected messages for showing appropriate labels 1011bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param selectedSet 1012bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param columnId 1013bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param defaultflag 1014bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true when the specified flagged message is selected 1015bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1016bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean testMultiple(Set<Long> selectedSet, int columnId, boolean defaultflag) { 1017bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final Cursor c = mListAdapter.getCursor(); 1018bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (c == null || c.isClosed()) { 1019bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 1020bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1021bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook c.moveToPosition(-1); 1022bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook while (c.moveToNext()) { 1023bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook long id = c.getInt(MessagesAdapter.COLUMN_ID); 1024bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (selectedSet.contains(Long.valueOf(id))) { 1025bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (c.getInt(columnId) == (defaultflag ? 1 : 0)) { 1026bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return true; 1027bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1028bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1029bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1030bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return false; 1031bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1032bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1033bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1034bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true if one or more non-starred messages are selected. 1035bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1036bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean doesSelectionContainNonStarredMessage() { 1037bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return testMultiple(mListAdapter.getSelectedSet(), MessagesAdapter.COLUMN_FAVORITE, 1038bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook false); 1039bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1040bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1041bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1042bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @return true if one or more read messages are selected. 1043bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1044bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean doesSelectionContainReadMessage() { 1045bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return testMultiple(mListAdapter.getSelectedSet(), MessagesAdapter.COLUMN_READ, true); 1046bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1047bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1048bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1049bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Implements a timed refresh of "stale" mailboxes. This should only happen when 1050bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * multiple conditions are true, including: 1051bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Only refreshable mailboxes. 1052bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Only when the mailbox is "stale" (currently set to 5 minutes since last refresh) 1053bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Note we do this even if it's a push account; even on Exchange only inbox can be pushed. 1054bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1055bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void autoRefreshStaleMailbox() { 1056bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!mIsRefreshable) { 1057bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Not refreshable (special box such as drafts, or magic boxes) 1058bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1059bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1060bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!mRefreshManager.isMailboxStale(getMailboxId())) { 1061bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1062bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1063bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onRefresh(false); 1064bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1065bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1066bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Implements {@link MessagesAdapter.Callback} */ 1067bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1068bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onAdapterFavoriteChanged(MessageListItem itemView, boolean newFavorite) { 1069bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mController.setMessageFavorite(itemView.mMessageId, newFavorite); 1070bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1071bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1072bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Implements {@link MessagesAdapter.Callback} */ 1073bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1074bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onAdapterSelectedChanged(MessageListItem itemView, boolean newSelected, 1075bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int mSelectedCount) { 1076bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateSelectionMode(); 1077bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1078bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1079bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void updateSearchHeader(Cursor cursor) { 1080bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessageListContext listContext = getListContext(); 1081bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!listContext.isSearch() || cursor == null) { 1082bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook UiUtilities.setVisibilitySafe(mSearchHeader, View.GONE); 1083bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1084bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1085bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1086bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook SearchResultsCursor searchCursor = (SearchResultsCursor) cursor; 1087bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook initSearchHeader(); 1088bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSearchHeader.setVisibility(View.VISIBLE); 1089bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook String header = mActivity.getString(R.string.search_header_text_fmt); 1090bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSearchHeaderText.setText(header); 1091bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int resultCount = searchCursor.getResultsCount(); 1092bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Don't show a negative value here; this means that the server request failed 1093bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // TODO Use some other text for this case (e.g. "search failed")? 1094bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (resultCount < 0) { 1095bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook resultCount = 0; 1096bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1097bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSearchHeaderCount.setText(UiUtilities.getMessageCountForUi( 1098bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mActivity, resultCount, false /* replaceZeroWithBlank */)); 1099bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1100bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1101bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private int determineFooterMode() { 1102bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int result = LIST_FOOTER_MODE_NONE; 1103bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if ((mMailbox == null) 1104bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook || (mMailbox.mType == Mailbox.TYPE_OUTBOX) 1105bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook || (mMailbox.mType == Mailbox.TYPE_DRAFTS)) { 1106bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return result; // No footer 1107bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1108bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mMailbox.mType == Mailbox.TYPE_SEARCH) { 1109bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Determine how many results have been loaded. 1110bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Cursor c = mListAdapter.getCursor(); 1111bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (c == null || c.isClosed()) { 1112bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Unknown yet - don't do anything. 1113bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return result; 1114bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1115bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int total = ((SearchResultsCursor) c).getResultsCount(); 1116bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int loaded = c.getCount(); 1117bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1118bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (loaded < total) { 1119bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook result = LIST_FOOTER_MODE_MORE; 1120bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1121bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else if (!mIsEasAccount) { 1122bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // IMAP, POP has "load more" for regular mailboxes. 1123bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook result = LIST_FOOTER_MODE_MORE; 1124bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1125bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return result; 1126bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1127bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1128bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void updateFooterView() { 1129bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Only called from onLoadFinished -- always has views. 1130bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int mode = determineFooterMode(); 1131bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mListFooterMode == mode) { 1132bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1133bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1134bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListFooterMode = mode; 1135bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1136bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ListView lv = getListView(); 1137bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mListFooterMode != LIST_FOOTER_MODE_NONE) { 1138bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lv.addFooterView(mListFooterView); 1139bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (getListAdapter() != null) { 1140bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Already have an adapter - reset it to force the mode. But save the scroll 1141bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // position so that we don't get kicked to the top. 1142bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Parcelable listState = lv.onSaveInstanceState(); 1143bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setListAdapter(mListAdapter); 1144bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lv.onRestoreInstanceState(listState); 1145bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1146bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1147bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListFooterProgress = mListFooterView.findViewById(R.id.progress); 1148bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListFooterText = (TextView) mListFooterView.findViewById(R.id.main_text); 1149bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1150bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lv.removeFooterView(mListFooterView); 1151bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1152bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateListFooter(); 1153bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1154bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1155bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1156bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Set the list footer text based on mode and the current "network active" status 1157bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1158bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void updateListFooter() { 1159bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mListFooterMode != LIST_FOOTER_MODE_NONE) { 1160bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int footerTextId = 0; 1161bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (mListFooterMode) { 1162bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case LIST_FOOTER_MODE_MORE: 1163bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean active = mRefreshManager.isMessageListRefreshing(getMailboxId()); 1164bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook footerTextId = active ? R.string.status_loading_messages 1165bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook : R.string.message_list_load_more_messages_action; 1166bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListFooterProgress.setVisibility(active ? View.VISIBLE : View.GONE); 1167bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1168bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1169bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListFooterText.setText(footerTextId); 1170bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1171bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1172bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1173bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1174bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Handle a click in the list footer, which changes meaning depending on what we're looking at. 1175bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1176bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void doFooterClick() { 1177bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (mListFooterMode) { 1178bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case LIST_FOOTER_MODE_NONE: // should never happen 1179bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1180bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case LIST_FOOTER_MODE_MORE: 1181bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onLoadMoreMessages(); 1182bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1183bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1184bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1185bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1186bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void showSendCommand(boolean show) { 1187bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (show != mShowSendCommand) { 1188bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mShowSendCommand = show; 1189bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mActivity.invalidateOptionsMenu(); 1190bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1191bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1192bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1193bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void updateMailboxSpecificActions() { 1194bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final boolean isOutbox = (getMailboxId() == Mailbox.QUERY_ALL_OUTBOX) 1195bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook || ((mMailbox != null) && (mMailbox.mType == Mailbox.TYPE_OUTBOX)); 1196bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showSendCommand(isOutbox && (mListAdapter != null) && (mListAdapter.getCount() > 0)); 1197bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1198bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // A null account/mailbox means we're in a combined view. We show the move icon there, 1199bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // even though it may be the case that we can't move messages from one of the mailboxes. 1200bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // There's no good way to tell that right now, though. 1201bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mShowMoveCommand = (mAccount == null || mAccount.supportsMoveMessages(getActivity())) 1202bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook && (mMailbox == null || mMailbox.canHaveMessagesMoved()); 1203bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1204bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Enable mailbox specific actions on the UIController level if needed. 1205bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mActivity.invalidateOptionsMenu(); 1206bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1207bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1208bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1209bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Adjusts message notification depending upon the state of the fragment and the currently 1210bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * viewed mailbox. If the fragment is resumed, notifications for the current mailbox may 1211bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * be suspended. Otherwise, notifications may be re-activated. Not all mailbox types are 1212bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * supported for notifications. These include (but are not limited to) special mailboxes 1213bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * such as {@link Mailbox#QUERY_ALL_DRAFTS}, {@link Mailbox#QUERY_ALL_FAVORITES}, etc... 1214bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1215bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * @param updateLastSeenKey If {@code true}, the last seen message key for the currently 1216bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * viewed mailbox will be updated. 1217bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1218bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void adjustMessageNotification(boolean updateLastSeenKey) { 1219bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final long accountId = getAccountId(); 1220bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final long mailboxId = getMailboxId(); 1221bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mailboxId == Mailbox.QUERY_ALL_INBOXES || mailboxId > 0) { 1222bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (updateLastSeenKey) { 1223bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.updateLastSeenMessageKey(mActivity, accountId); 1224bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1225bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook NotificationController notifier = NotificationController.getInstance(mActivity); 1226bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook notifier.suspendMessageNotification(mResumed, accountId); 1227bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1228bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1229bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1230bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void startLoading() { 1231bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 1232bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, this + " startLoading"); 1233bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1234bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Clear the list. (ListFragment will show the "Loading" animation) 1235bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showSendCommand(false); 1236bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateSearchHeader(null); 1237bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1238bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Start loading... 1239bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final LoaderManager lm = getLoaderManager(); 1240bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lm.initLoader(LOADER_ID_MESSAGES_LOADER, null, LOADER_CALLBACKS); 1241bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1242bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1243bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Timeout to show a warning, since some IMAP searches could take a long time. */ 1244bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final int SEARCH_WARNING_DELAY_MS = 10000; 1245bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1246bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void onSearchLoadTimeout() { 1247bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Search is taking too long. Show an error message. 1248bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook ViewGroup root = (ViewGroup) getView(); 1249bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Activity host = getActivity(); 1250bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (root != null && host != null) { 1251bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListPanel.setVisibility(View.GONE); 1252bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mWarningContainer = (ViewGroup) LayoutInflater.from(host).inflate( 1253bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook R.layout.message_list_warning, root, false); 1254bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook TextView title = UiUtilities.getView(mWarningContainer, R.id.message_title); 1255bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook TextView message = UiUtilities.getView(mWarningContainer, R.id.message_warning); 1256bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook title.setText(R.string.search_slow_warning_title); 1257bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook message.setText(R.string.search_slow_warning_message); 1258bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook root.addView(mWarningContainer); 1259bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1260bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1261bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1262bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1263bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Loader callbacks for message list. 1264bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1265bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private final LoaderManager.LoaderCallbacks<Cursor> LOADER_CALLBACKS = 1266bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook new LoaderManager.LoaderCallbacks<Cursor>() { 1267bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1268bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public Loader<Cursor> onCreateLoader(int id, Bundle args) { 1269bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final MessageListContext listContext = getListContext(); 1270bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 1271bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, MessageListFragment.this 1272bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook + " onCreateLoader(messages) listContext=" + listContext); 1273bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1274bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1275bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mListContext.isSearch()) { 1276bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final MessageListContext searchInfo = mListContext; 1277bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1278bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Search results are not primed with local data, and so will usually be slow. 1279bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // In some cases, they could take a long time to return, so we need to be robust. 1280bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setListShownNoAnimation(false); 1281bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.getMainThreadHandler().postDelayed(new Runnable() { 1282bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1283bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void run() { 1284bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mListContext != searchInfo) { 1285bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Different list is being shown now. 1286bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1287bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1288bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!mIsFirstLoad) { 1289bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Something already returned. No need to do anything. 1290bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1291bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1292bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onSearchLoadTimeout(); 1293bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1294bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook }, SEARCH_WARNING_DELAY_MS); 1295bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1296bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1297bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mIsFirstLoad = true; 1298bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return MessagesAdapter.createLoader(getActivity(), listContext); 1299bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1300bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1301bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1302bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onLoadFinished(Loader<Cursor> loader, Cursor c) { 1303bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 1304bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, MessageListFragment.this 1305bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook + " onLoadFinished(messages) mailboxId=" + getMailboxId()); 1306bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1307bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MessagesAdapter.MessagesCursor cursor = (MessagesAdapter.MessagesCursor) c; 1308bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1309bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Update the list 1310bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.swapCursor(cursor); 1311bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1312bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!cursor.mIsFound) { 1313bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onMailboxNotFound(mIsFirstLoad); 1314bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1315bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1316bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1317bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Get the "extras" part. 1318bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAccount = cursor.mAccount; 1319bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMailbox = cursor.mMailbox; 1320bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mIsEasAccount = cursor.mIsEasAccount; 1321bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mIsRefreshable = cursor.mIsRefreshable; 1322bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCountTotalAccounts = cursor.mCountTotalAccounts; 1323bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1324bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // If this is a search result, open the first message unless we are 1325bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // restoring the message position from saved state, in which case, 1326bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // mSelectedMessageId was already set and should be respected. 1327bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (UiUtilities.useTwoPane(getActivity()) && mIsFirstLoad && mListContext.isSearch() 1328bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook && cursor.getCount() > 0 1329bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook && UiUtilities.showTwoPaneSearchResults(getActivity()) 1330bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook && mSelectedMessageId == -1) { 1331bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook cursor.moveToFirst(); 1332bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onMessageOpen(getMailboxId(), cursor.getLong(MessagesAdapter.COLUMN_ID)); 1333bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1334bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1335bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Suspend message notifications as long as we're resumed 1336bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook adjustMessageNotification(false); 1337bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1338bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // If this is a search mailbox, set the query; otherwise, clear it 1339bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mIsFirstLoad) { 1340bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mMailbox != null && mMailbox.mType == Mailbox.TYPE_SEARCH) { 1341bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.setQuery(getListContext().getSearchParams().mFilter); 1342bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSearchedMailbox = ((SearchResultsCursor) c).getSearchedMailbox(); 1343bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1344bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.setQuery(null); 1345bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSearchedMailbox = null; 1346bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1347bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateMailboxSpecificActions(); 1348bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1349bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Show chips if combined view. 1350bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.setShowColorChips(isCombinedMailbox() && mCountTotalAccounts > 1); 1351bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1352bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1353bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Various post processing... 1354bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateSearchHeader(cursor); 1355bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook autoRefreshStaleMailbox(); 1356bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateFooterView(); 1357bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateSelectionMode(); 1358bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1359bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // We want to make visible the selection only for the first load. 1360bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Re-load caused by content changed events shouldn't scroll the list. 1361bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook highlightSelectedMessage(mIsFirstLoad); 1362bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1363bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mIsFirstLoad) { 1364bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook UiUtilities.setVisibilitySafe(mWarningContainer, View.GONE); 1365bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListPanel.setVisibility(View.VISIBLE); 1366bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1367bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Setting the adapter will automatically transition from "Loading" to showing 1368bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // the list, which could show "No messages". Avoid showing that on the first sync, 1369bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // if we know we're still potentially loading more. 1370bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!isEmptyAndLoading(cursor)) { 1371bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setListAdapter(mListAdapter); 1372bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1373bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else if ((getListAdapter() == null) && !isEmptyAndLoading(cursor)) { 1374bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook setListAdapter(mListAdapter); 1375bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1376bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1377bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Restore the state -- this step has to be the last, because Some of the 1378bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // "post processing" seems to reset the scroll position. 1379bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mSavedListState != null) { 1380bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook getListView().onRestoreInstanceState(mSavedListState); 1381bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSavedListState = null; 1382bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1383bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1384bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mIsFirstLoad = false; 1385bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1386bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1387bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1388bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Determines whether or not the list is empty, but we're still potentially loading data. 1389bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * This represents an ambiguous state where we may not want to show "No messages", since 1390bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * it may still just be loading. 1391bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1392bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private boolean isEmptyAndLoading(Cursor cursor) { 1393bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mMailbox == null) return false; 1394bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return cursor.getCount() == 0 && mRefreshManager.isMessageListRefreshing(mMailbox.mId); 1395bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1396bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1397bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1398bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onLoaderReset(Loader<Cursor> loader) { 1399bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (Logging.DEBUG_LIFECYCLE && Email.DEBUG) { 1400bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Log.d(Logging.LOG_TAG, MessageListFragment.this 1401bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook + " onLoaderReset(messages)"); 1402bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1403bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mListAdapter.swapCursor(null); 1404bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAccount = null; 1405bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMailbox = null; 1406bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSearchedMailbox = null; 1407bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCountTotalAccounts = 0; 1408bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1409bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook }; 1410bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1411bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1412bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Show/hide the "selection" action mode, according to the number of selected messages and 1413bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * the visibility of the fragment. 1414bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Also update the content (title and menus) if necessary. 1415bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1416bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void updateSelectionMode() { 1417bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final int numSelected = getSelectedCount(); 1418bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if ((numSelected == 0) || mDisableCab || !isViewCreated()) { 1419bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook finishSelectionMode(); 1420bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1421bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1422bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (isInSelectionMode()) { 1423bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateSelectionModeView(); 1424bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } else { 1425bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mLastSelectionModeCallback = new SelectionModeCallback(); 1426bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook getActivity().startActionMode(mLastSelectionModeCallback); 1427bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1428bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1429bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1430bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1431bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1432bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Finish the "selection" action mode. 1433bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * 1434bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Note this method finishes the contextual mode, but does *not* clear the selection. 1435bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * If you want to do so use {@link #onDeselectAll()} instead. 1436bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1437bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void finishSelectionMode() { 1438bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (isInSelectionMode()) { 1439bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mLastSelectionModeCallback.mClosedByUser = false; 1440bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSelectionMode.finish(); 1441bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1442bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1443bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1444bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** Update the "selection" action mode bar */ 1445bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void updateSelectionModeView() { 1446bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSelectionMode.invalidate(); 1447bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1448bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1449bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class SelectionModeCallback implements ActionMode.Callback { 1450bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MenuItem mMarkRead; 1451bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MenuItem mMarkUnread; 1452bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MenuItem mAddStar; 1453bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MenuItem mRemoveStar; 1454bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private MenuItem mMove; 1455bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1456bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /* package */ boolean mClosedByUser = true; 1457bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1458bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1459bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onCreateActionMode(ActionMode mode, Menu menu) { 1460bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSelectionMode = mode; 1461bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1462bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook MenuInflater inflater = getActivity().getMenuInflater(); 1463bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook inflater.inflate(R.menu.message_list_fragment_cab_options, menu); 1464bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMarkRead = menu.findItem(R.id.mark_read); 1465bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMarkUnread = menu.findItem(R.id.mark_unread); 1466bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAddStar = menu.findItem(R.id.add_star); 1467bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRemoveStar = menu.findItem(R.id.remove_star); 1468bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMove = menu.findItem(R.id.move); 1469bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return true; 1470bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1471bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1472bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1473bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 1474bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook int num = getSelectedCount(); 1475bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Set title -- "# selected" 1476bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSelectionMode.setTitle(getActivity().getResources().getQuantityString( 1477bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook R.plurals.message_view_selected_message_count, num, num)); 1478bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1479bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Show appropriate menu items. 1480bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean nonStarExists = doesSelectionContainNonStarredMessage(); 1481bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook boolean readExists = doesSelectionContainReadMessage(); 1482bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMarkRead.setVisible(!readExists); 1483bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMarkUnread.setVisible(readExists); 1484bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mAddStar.setVisible(nonStarExists); 1485bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mRemoveStar.setVisible(!nonStarExists); 1486bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mMove.setVisible(mShowMoveCommand); 1487bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return true; 1488bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1489bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1490bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1491bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 1492bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Set<Long> selectedConversations = mListAdapter.getSelectedSet(); 1493bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (selectedConversations.isEmpty()) return true; 1494bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook switch (item.getItemId()) { 1495bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.mark_read: 1496bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Note - marking as read does not trigger auto-advance. 1497bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook toggleRead(selectedConversations); 1498bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1499bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.mark_unread: 1500bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onAdvancingOpAccepted(selectedConversations); 1501bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook toggleRead(selectedConversations); 1502bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1503bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.add_star: 1504bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.remove_star: 1505bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // TODO: removing a star can be a destructive command and cause auto-advance 1506bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // if the current mailbox shown is favorites. 1507bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook toggleFavorite(selectedConversations); 1508bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1509bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.delete: 1510bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mCallback.onAdvancingOpAccepted(selectedConversations); 1511bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook deleteMessages(selectedConversations); 1512bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1513bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook case R.id.move: 1514bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook showMoveMessagesDialog(selectedConversations); 1515bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1516bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1517bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return true; 1518bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1519bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1520bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1521bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onDestroyActionMode(ActionMode mode) { 1522bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Clear this before onDeselectAll() to prevent onDeselectAll() from trying to close the 1523bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // contextual mode again. 1524bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook mSelectionMode = null; 1525bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mClosedByUser) { 1526bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // Clear selection, only when the contextual mode is explicitly closed by the user. 1527bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // 1528bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // We close the contextual mode when the fragment becomes temporary invisible 1529bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // (i.e. mIsVisible == false) too, in which case we want to keep the selection. 1530bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook onDeselectAll(); 1531bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1532bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1533bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1534bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1535bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private class RefreshListener implements RefreshManager.Listener { 1536bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1537bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onMessagingError(long accountId, long mailboxId, String message) { 1538bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1539bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1540bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook @Override 1541bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook public void onRefreshStatusChanged(long accountId, long mailboxId) { 1542bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook updateListFooter(); 1543bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1544bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1545bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1546bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook /** 1547bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook * Highlight the selected message. 1548bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook */ 1549bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook private void highlightSelectedMessage(boolean ensureSelectionVisible) { 1550bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (!isViewCreated()) { 1551bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1552bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1553bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1554bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final ListView lv = getListView(); 1555bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (mSelectedMessageId == -1) { 1556bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook // No message selected 1557bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lv.clearChoices(); 1558bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook return; 1559bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1560bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook 1561bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook final int count = lv.getCount(); 1562bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook for (int i = 0; i < count; i++) { 1563bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (lv.getItemIdAtPosition(i) != mSelectedMessageId) { 1564bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook continue; 1565bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1566bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook lv.setItemChecked(i, true); 1567bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook if (ensureSelectionVisible) { 1568bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook Utility.listViewSmoothScrollToPosition(getActivity(), lv, i); 1569bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1570bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook break; 1571bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1572bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook } 1573bc47398187c6ffd132435e51d8d61e6ec79a79dbPaul Westbrook} 1574