ConversationPagerAdapter.java revision 3825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bb
1632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang/* 2632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Copyright (C) 2012 Google Inc. 3632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Licensed to The Android Open Source Project. 4632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * 5632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Licensed under the Apache License, Version 2.0 (the "License"); 6632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * you may not use this file except in compliance with the License. 7632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * You may obtain a copy of the License at 8632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * 9632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * http://www.apache.org/licenses/LICENSE-2.0 10632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * 11632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Unless required by applicable law or agreed to in writing, software 12632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * distributed under the License is distributed on an "AS IS" BASIS, 13632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * See the License for the specific language governing permissions and 15632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * limitations under the License. 16632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 17632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 18632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangpackage com.android.mail.browse; 19632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 20632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.app.Fragment; 21632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.app.FragmentManager; 2222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huangimport android.content.res.Resources; 23632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.database.Cursor; 24632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.database.DataSetObserver; 25632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.os.Bundle; 26632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.os.Parcelable; 2722ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huangimport android.support.v4.view.ViewPager; 28632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.view.ViewGroup; 29632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 3022ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huangimport com.android.mail.R; 31632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.Account; 32632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.Conversation; 33632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.Folder; 34632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.UIProvider; 35090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huangimport com.android.mail.ui.ActivityController; 36632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.ui.ConversationViewFragment; 37632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.utils.FragmentStatePagerAdapter2; 38b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 39632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.utils.LogUtils; 40ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huangimport com.android.mail.utils.Utils; 41632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 42632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangpublic class ConversationPagerAdapter extends FragmentStatePagerAdapter2 { 43632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 44632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private final DataSetObserver mListObserver = new ListObserver(); 45090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang private final DataSetObserver mFolderObserver = new FolderObserver(); 46090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang private ActivityController mController; 47632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private final Bundle mCommonFragmentArgs; 48632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private final Conversation mInitialConversation; 49b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang private final Account mAccount; 50b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang private final Folder mFolder; 51632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang /** 52632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * In singleton mode, this adapter ignores the cursor contents and size, and acts as if the 531ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * data set size is exactly size=1, with {@link #getDefaultConversation()} at position 0. 54632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 55632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private boolean mSingletonMode = true; 56632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang /** 571ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * Similar to singleton mode, but once enabled, detached mode is permanent for this adapter. 581ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang */ 591ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private boolean mDetachedMode = false; 601ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang /** 61632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Adapter methods may trigger a data set change notification in the middle of a ViewPager 62632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * update, but they are not safe to handle, so we have to ignore them. This will not ignore 63632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * pager-external updates; it's impossible to be notified of an external change during 64632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * an update. 65632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * 66632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * TODO: Queue up changes like this, if there ever are any that actually modify the data set. 67632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Right now there are none. Such a change would have to be of the form: instantiation or 68632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * setPrimary somehow adds or removes items from the conversation cursor. Crazy! 69632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 70632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private boolean mSafeToNotify; 7122ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang /** 7222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * Need to keep this around to look up pager title strings. 7322ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang */ 7422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang private Resources mResources; 7522ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang /** 7622ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * This isn't great to create a circular dependency, but our usage of {@link #getPageTitle(int)} 7722ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * requires knowing which page is the currently visible to dynamically name offscreen pages 7822ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * "newer" and "older". And {@link #setPrimaryItem(ViewGroup, int, Object)} does not work well 7922ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * because it isn't updated as often as {@link ViewPager#getCurrentItem()} is. 8022ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * <p> 8122ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * We must be careful to null out this reference when the pager and adapter are decoupled to 8222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * minimize dangling references. 8322ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang */ 8422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang private ViewPager mPager; 85632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 86b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook private static final String LOG_TAG = LogTag.getLogTag(); 87632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 881ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private static final String BUNDLE_DETACHED_MODE = 891ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang ConversationPagerAdapter.class.getName() + "-detachedmode"; 901ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 9122ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang public ConversationPagerAdapter(Resources res, FragmentManager fm, Account account, 9222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang Folder folder, Conversation initialConversation) { 93632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super(fm, false /* enableSavedStates */); 9422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mResources = res; 95632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mCommonFragmentArgs = ConversationViewFragment.makeBasicArgs(account, folder); 96632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mInitialConversation = initialConversation; 97b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang mAccount = account; 98b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang mFolder = folder; 99b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang } 100b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang 101b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang public boolean matches(Account account, Folder folder) { 102b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang return mAccount != null && mFolder != null && mAccount.matches(account) 103b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang && mFolder.equals(folder); 104632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 105632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 106632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void setSingletonMode(boolean enabled) { 107632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (mSingletonMode != enabled) { 108632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mSingletonMode = enabled; 109632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang notifyDataSetChanged(); 110632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 111632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 112632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 113632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public boolean isSingletonMode() { 1141ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return mSingletonMode; 1151ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 1161ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 1171ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang public boolean isPagingDisabled() { 1181ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return mSingletonMode || mDetachedMode || getCursor() == null; 119e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang } 120e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang 121e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang private Cursor getCursor() { 122090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (mController == null) { 123192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // Happens when someone calls setActivityController(null) on us. This is done in 124192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // ConversationPagerController.stopListening() to indicate that the Conversation View 125192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // is going away *very* soon. 1263825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang LogUtils.i(LOG_TAG, "Pager adapter has a null controller. If the conversation view" 127192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal + " is going away, this is fine. Otherwise, the state is inconsistent"); 1288775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return null; 129e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang } 130e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang 131090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang return mController.getConversationListCursor(); 132632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 133632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 134632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 135632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public Fragment getItem(int position) { 136632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final Conversation c; 137632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 1381ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (isPagingDisabled()) { 139632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // cursor-less adapter is a size-1 cursor that points to mInitialConversation. 140632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // sanity-check 141632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (position != 0) { 142632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.wtf(LOG_TAG, "pager cursor is null and position is non-zero: %d", 143632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang position); 144632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 1451ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang c = getDefaultConversation(); 146c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal c.position = 0; 147632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else { 148e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang final Cursor cursor = getCursor(); 1498775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang if (cursor == null) { 1508775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang LogUtils.wtf(LOG_TAG, "unable to get ConversationCursor, pos=%d", position); 1518775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return null; 1528775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang } 153e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang if (!cursor.moveToPosition(position)) { 154632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.wtf(LOG_TAG, "unable to seek to ConversationCursor pos=%d (%s)", position, 155e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang cursor); 156632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return null; 157632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 158632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // TODO: switch to something like MessageCursor or AttachmentCursor 159632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // to re-use these models 160e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang c = new Conversation(cursor); 161c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal c.position = position; 162632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 163632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final Fragment f = ConversationViewFragment.newInstance(mCommonFragmentArgs, c); 164632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.getItem, frag=%s subj=%s", f, c.subject); 165632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return f; 166632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 167632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 168632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 169632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public int getCount() { 1701ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (isPagingDisabled()) { 1713825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang LogUtils.d(LOG_TAG, "IN CPA.getCount, returning 1 (effective singleton). cursor=%s", 1723825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang getCursor()); 1738775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return 1; 1748775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang } 1758775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang final Cursor cursor = getCursor(); 1768775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang if (cursor == null) { 1778775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return 0; 1788775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang } 1798775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return cursor.getCount(); 180632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 181632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 182632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 183632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public int getItemPosition(Object item) { 184632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (!(item instanceof ConversationViewFragment)) { 185632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.wtf(LOG_TAG, "getItemPosition received unexpected item: %s", item); 186632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 187632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 188632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final ConversationViewFragment fragment = (ConversationViewFragment) item; 189632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return getConversationPosition(fragment.getConversation()); 190632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 191632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 192632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 193632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void setPrimaryItem(ViewGroup container, int position, Object object) { 194632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.setPrimaryItem, pos=%d, frag=%s", position, 195632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang object); 196632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.setPrimaryItem(container, position, object); 197632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 198632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 199632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 200632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public CharSequence getPageTitle(int position) { 20122ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang final String title; 20222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang final int currentPosition = mPager.getCurrentItem(); 203632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 2041ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (isPagingDisabled()) { 20568459a7b3265da5002ff331529f12f6b408c9b03Andy Huang title = null; 20668459a7b3265da5002ff331529f12f6b408c9b03Andy Huang } else if (position == currentPosition) { 207090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang int total = getCount(); 208090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (mController != null) { 209090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang final Folder f = mController.getFolder(); 210090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (f != null && f.totalCount > total) { 211090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang total = f.totalCount; 212090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 213090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 214090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang title = mResources.getString(R.string.conversation_count, position + 1, total); 21522ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang } else { 21668459a7b3265da5002ff331529f12f6b408c9b03Andy Huang title = mResources.getString(position < currentPosition ? 21722ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang R.string.conversation_newer : R.string.conversation_older); 21822ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang } 21922ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang return title; 220632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 221632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 222632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 223632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public Parcelable saveState() { 2241ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.saveState. this=%s", this); 2251ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang Bundle state = (Bundle) super.saveState(); // superclass uses a Bundle 2261ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (state == null) { 2271ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang state = new Bundle(); 2281ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 2291ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang state.putBoolean(BUNDLE_DETACHED_MODE, mDetachedMode); 2301ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return state; 231632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 232632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 233632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 234632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void restoreState(Parcelable state, ClassLoader loader) { 2351ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.restoreState. this=%s", this); 236632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.restoreState(state, loader); 2371ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (state != null) { 2381ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang Bundle b = (Bundle) state; 2391ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang b.setClassLoader(loader); 2401ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mDetachedMode = b.getBoolean(BUNDLE_DETACHED_MODE); 2411ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 242632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 243632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 244632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 245632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void startUpdate(ViewGroup container) { 246632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mSafeToNotify = false; 247632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.startUpdate(container); 248632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 249632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 250632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 251632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void finishUpdate(ViewGroup container) { 252632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.finishUpdate(container); 253632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mSafeToNotify = true; 254632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 255632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 256632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 257632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void notifyDataSetChanged() { 258632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (!mSafeToNotify) { 259632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.notifyDataSetChanged, ignoring unsafe update"); 260632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return; 261632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2621ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 2631ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // when the currently visible item disappears from the dataset: 2641ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // if the new version of the currently visible item has zero messages: 2651ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // notify the list controller so it can handle this 'current conversation gone' case 2661ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // (by backing out of conversation mode) 2671ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // else 2681ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // 'detach' the conversation view from the cursor, keeping the current item as-is but 2691ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // disabling swipe (effectively the same as singleton mode) 2701ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (mController != null) { 2711ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang final Conversation currConversation = mController.getCurrentConversation(); 2721ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang final int pos = getConversationPosition(currConversation); 2731ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (pos == POSITION_NONE) { 2741ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // enable detached mode and do no more here. the fragment itself will figure out 2751ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // if the conversation is empty (using message list cursor) and back out if needed. 2761ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mDetachedMode = true; 2771ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang LogUtils.i(LOG_TAG, "CPA: current conv is gone, reverting to detached mode. c=%s", 2781ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang currConversation.uri); 2791ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 2801ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 2811ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 282632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.notifyDataSetChanged(); 2831ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 2841ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // notify unaffected fragment items of the change, so they can re-render 2851ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // (the change may have been to the labels for a single conversation, for example) 286632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 287632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 288632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 289632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void setItemVisible(Fragment item, boolean visible) { 290632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.setItemVisible(item, visible); 291632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final ConversationViewFragment fragment = (ConversationViewFragment) item; 292632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang fragment.setExtraUserVisibleHint(visible); 293632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 294090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (visible && mController != null) { 295632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final Conversation c = fragment.getConversation(); 296632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "pager adapter setting current conv: %s (%s)", c.subject, item); 297090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mController.setCurrentConversation(c); 298632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 299632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 300632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 3011ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private Conversation getDefaultConversation() { 3021ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang Conversation c = (mController != null) ? mController.getCurrentConversation() : null; 3031ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (c == null) { 3041ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang c = mInitialConversation; 3051ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 3061ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return c; 3071ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 3081ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 309632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public int getConversationPosition(Conversation conv) { 3101ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (isPagingDisabled()) { 3117ce62d32cec32b94b3e7fd554ed017dc9bd998e7Andy Huang if (getCursor() == null) { 3127ce62d32cec32b94b3e7fd554ed017dc9bd998e7Andy Huang return POSITION_NONE; 3137ce62d32cec32b94b3e7fd554ed017dc9bd998e7Andy Huang } 3147ce62d32cec32b94b3e7fd554ed017dc9bd998e7Andy Huang 3151ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (conv != getDefaultConversation()) { 3161ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang LogUtils.d(LOG_TAG, "unable to find conversation in singleton mode. c=%s", 317632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang conv); 318632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return POSITION_NONE; 319632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 320632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return 0; 321632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 322632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 323e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang final Cursor cursor = getCursor(); 3248775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang if (cursor == null) { 3258775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return POSITION_NONE; 3268775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang } 327e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang 328e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang final boolean networkWasEnabled = Utils.disableConversationCursorNetworkAccess(cursor); 329ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang 330ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang int result = POSITION_NONE; 331632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang int pos = -1; 332e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang while (cursor.moveToPosition(++pos)) { 333e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang final long id = cursor.getLong(UIProvider.CONVERSATION_ID_COLUMN); 334632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (conv.id == id) { 335632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "pager adapter found repositioned convo '%s' at pos=%d", 336632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang conv.subject, pos); 337ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang result = pos; 338ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang break; 339632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 340632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 341ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang 342ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang if (networkWasEnabled) { 343e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang Utils.enableConversationCursorNetworkAccess(cursor); 344ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang } 345ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang 346ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang return result; 347632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 348632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 34922ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang public void setPager(ViewPager pager) { 35022ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mPager = pager; 35122ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang } 35222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang 353090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public void setActivityController(ActivityController controller) { 354090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (mController != null) { 355090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mController.unregisterConversationListObserver(mListObserver); 356860164409d7f9e4f726ed4edb2ed77afc6873ad5Andy Huang mController.unregisterFolderObserver(mFolderObserver); 357632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 358090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mController = controller; 359090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (mController != null) { 360090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mController.registerConversationListObserver(mListObserver); 361860164409d7f9e4f726ed4edb2ed77afc6873ad5Andy Huang mController.registerFolderObserver(mFolderObserver); 362632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 363e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang notifyDataSetChanged(); 364632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else { 365e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang // We're being torn down; do not notify. 366e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang // Let the pager controller manage pager lifecycle. 367632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 368632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 369632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 370090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang // update the pager title strip as the Folder's conversation count changes 371090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang private class FolderObserver extends DataSetObserver { 372090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang @Override 373090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public void onChanged() { 374090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang notifyDataSetChanged(); 375090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 376090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 377090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang 378632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // update the pager dataset as the Controller's cursor changes 379632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private class ListObserver extends DataSetObserver { 380632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 381632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onChanged() { 382e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang notifyDataSetChanged(); 383632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 384632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 385632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onInvalidated() { 386632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 387632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 388632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 389632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang} 390