ConversationPagerAdapter.java revision 18176786f320b4d4312ad1682da057434f201c13
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; 35f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.ui.AbstractConversationViewFragment; 36090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huangimport com.android.mail.ui.ActivityController; 37632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.ui.ConversationViewFragment; 38351ad4e87e0b0b98df9ca88266a8a63541dc5a81Andy Huangimport com.android.mail.ui.SecureConversationViewFragment; 39632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.utils.FragmentStatePagerAdapter2; 40b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 41632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.utils.LogUtils; 42632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 437d64612104fd861474a09994f13768360f92041dAndy Huangpublic class ConversationPagerAdapter extends FragmentStatePagerAdapter2 447d64612104fd861474a09994f13768360f92041dAndy Huang implements ViewPager.OnPageChangeListener { 45632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 46632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private final DataSetObserver mListObserver = new ListObserver(); 47090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang private final DataSetObserver mFolderObserver = new FolderObserver(); 48090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang private ActivityController mController; 49632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private final Bundle mCommonFragmentArgs; 50632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private final Conversation mInitialConversation; 51b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang private final Account mAccount; 52b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang private final Folder mFolder; 53632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang /** 54632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * In singleton mode, this adapter ignores the cursor contents and size, and acts as if the 551ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * data set size is exactly size=1, with {@link #getDefaultConversation()} at position 0. 56632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 57632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private boolean mSingletonMode = true; 58632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang /** 591ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang * Similar to singleton mode, but once enabled, detached mode is permanent for this adapter. 601ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang */ 611ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private boolean mDetachedMode = false; 621ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang /** 63632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Adapter methods may trigger a data set change notification in the middle of a ViewPager 64632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * update, but they are not safe to handle, so we have to ignore them. This will not ignore 65632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * pager-external updates; it's impossible to be notified of an external change during 66632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * an update. 67632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * 68632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * TODO: Queue up changes like this, if there ever are any that actually modify the data set. 69632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Right now there are none. Such a change would have to be of the form: instantiation or 70632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * setPrimary somehow adds or removes items from the conversation cursor. Crazy! 71632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 72632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private boolean mSafeToNotify; 7322ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang /** 7422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * Need to keep this around to look up pager title strings. 7522ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang */ 7622ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang private Resources mResources; 7722ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang /** 7822ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * This isn't great to create a circular dependency, but our usage of {@link #getPageTitle(int)} 7922ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * requires knowing which page is the currently visible to dynamically name offscreen pages 8022ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * "newer" and "older". And {@link #setPrimaryItem(ViewGroup, int, Object)} does not work well 8122ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * because it isn't updated as often as {@link ViewPager#getCurrentItem()} is. 8222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * <p> 8322ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * We must be careful to null out this reference when the pager and adapter are decoupled to 8422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang * minimize dangling references. 8522ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang */ 8622ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang private ViewPager mPager; 87f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp private boolean mSanitizedHtml; 88632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 89b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook private static final String LOG_TAG = LogTag.getLogTag(); 90632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 911ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private static final String BUNDLE_DETACHED_MODE = 921ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang ConversationPagerAdapter.class.getName() + "-detachedmode"; 931ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 9422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang public ConversationPagerAdapter(Resources res, FragmentManager fm, Account account, 9522ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang Folder folder, Conversation initialConversation) { 96632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super(fm, false /* enableSavedStates */); 9722ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mResources = res; 98f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mCommonFragmentArgs = AbstractConversationViewFragment.makeBasicArgs(account, folder); 99632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mInitialConversation = initialConversation; 100b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang mAccount = account; 101b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang mFolder = folder; 102f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp mSanitizedHtml = mAccount.supportsCapability 103f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp (UIProvider.AccountCapabilities.SANITIZED_HTML); 104b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang } 105b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang 106b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang public boolean matches(Account account, Folder folder) { 107b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang return mAccount != null && mFolder != null && mAccount.matches(account) 108b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang && mFolder.equals(folder); 109632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 110632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 111632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void setSingletonMode(boolean enabled) { 112632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (mSingletonMode != enabled) { 113632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mSingletonMode = enabled; 114632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang notifyDataSetChanged(); 115632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 116632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 117632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 118632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public boolean isSingletonMode() { 1191ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return mSingletonMode; 1201ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 1211ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 12277fb5be70d76f22a64850aa7a40f6a9553960e4emindyp public boolean isDetached() { 12377fb5be70d76f22a64850aa7a40f6a9553960e4emindyp return mDetachedMode; 12477fb5be70d76f22a64850aa7a40f6a9553960e4emindyp } 12577fb5be70d76f22a64850aa7a40f6a9553960e4emindyp 1265440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal /** 1275440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal * Returns true if singleton mode or detached mode have been enabled, or if the current cursor 1285440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal * is null. 1295440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal * @param cursor the current conversation cursor (obtained through {@link #getCursor()}. 1305440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal * @return 1315440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal */ 1325440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal public boolean isPagingDisabled(Cursor cursor) { 1335440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal return mSingletonMode || mDetachedMode || cursor == null; 134e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang } 135e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang 1364de145bb568b6963d374fa0bac199218dc494186Paul Westbrook private ConversationCursor getCursor() { 137a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal if (mDetachedMode) { 138a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // In detached mode, the pager is decoupled from the cursor. Nothing should rely on the 139a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // cursor at this point. 140a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal return null; 141a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal } 142090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (mController == null) { 143192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // Happens when someone calls setActivityController(null) on us. This is done in 144192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // ConversationPagerController.stopListening() to indicate that the Conversation View 145192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal // is going away *very* soon. 1463825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang LogUtils.i(LOG_TAG, "Pager adapter has a null controller. If the conversation view" 147192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal + " is going away, this is fine. Otherwise, the state is inconsistent"); 1488775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return null; 149e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang } 150e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang 151090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang return mController.getConversationListCursor(); 152632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 153632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 154632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 155632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public Fragment getItem(int position) { 156632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final Conversation c; 1575440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal final Cursor cursor = getCursor(); 158632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 1595440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal if (isPagingDisabled(cursor)) { 160632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // cursor-less adapter is a size-1 cursor that points to mInitialConversation. 161632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // sanity-check 162632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (position != 0) { 163632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.wtf(LOG_TAG, "pager cursor is null and position is non-zero: %d", 164632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang position); 165632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 1661ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang c = getDefaultConversation(); 167c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal c.position = 0; 168632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else { 169e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang if (!cursor.moveToPosition(position)) { 170632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.wtf(LOG_TAG, "unable to seek to ConversationCursor pos=%d (%s)", position, 171e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang cursor); 172632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return null; 173632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 174632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // TODO: switch to something like MessageCursor or AttachmentCursor 175632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // to re-use these models 176e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang c = new Conversation(cursor); 177c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal c.position = position; 178632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 179f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp final Fragment f = getConversationViewFragment(c); 180632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.getItem, frag=%s subj=%s", f, c.subject); 181632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return f; 182632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 183632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 184f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp private AbstractConversationViewFragment getConversationViewFragment(Conversation c) { 185f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp if (mSanitizedHtml) { 186f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp return ConversationViewFragment.newInstance(mCommonFragmentArgs, c); 187f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } else { 188f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp return SecureConversationViewFragment.newInstance(mCommonFragmentArgs, c); 189f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 190f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp } 191f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp 192632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 193632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public int getCount() { 1945440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal final Cursor cursor = getCursor(); 1955440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal if (isPagingDisabled(cursor)) { 1963825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang LogUtils.d(LOG_TAG, "IN CPA.getCount, returning 1 (effective singleton). cursor=%s", 1975440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal cursor); 1988775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return 1; 1998775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang } 2008775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return cursor.getCount(); 201632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 202632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 203632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 204632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public int getItemPosition(Object item) { 205f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp if (!(item instanceof AbstractConversationViewFragment)) { 206632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.wtf(LOG_TAG, "getItemPosition received unexpected item: %s", item); 207632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 208632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 209f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp final AbstractConversationViewFragment fragment = (AbstractConversationViewFragment) item; 210632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return getConversationPosition(fragment.getConversation()); 211632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 212632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 213632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 214632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void setPrimaryItem(ViewGroup container, int position, Object object) { 215632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.setPrimaryItem, pos=%d, frag=%s", position, 216632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang object); 217632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.setPrimaryItem(container, position, object); 218632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 219632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 220632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 221632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public CharSequence getPageTitle(int position) { 22222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang final String title; 22322ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang final int currentPosition = mPager.getCurrentItem(); 2245440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal final Cursor cursor = getCursor(); 2255440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal if (isPagingDisabled(cursor)) { 22668459a7b3265da5002ff331529f12f6b408c9b03Andy Huang title = null; 22768459a7b3265da5002ff331529f12f6b408c9b03Andy Huang } else if (position == currentPosition) { 228090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang int total = getCount(); 229090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (mController != null) { 230090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang final Folder f = mController.getFolder(); 231090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (f != null && f.totalCount > total) { 232090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang total = f.totalCount; 233090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 234090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 235090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang title = mResources.getString(R.string.conversation_count, position + 1, total); 23622ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang } else { 23768459a7b3265da5002ff331529f12f6b408c9b03Andy Huang title = mResources.getString(position < currentPosition ? 23822ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang R.string.conversation_newer : R.string.conversation_older); 23922ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang } 24022ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang return title; 241632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 242632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 243632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 244632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public Parcelable saveState() { 2451ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.saveState. this=%s", this); 2461ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang Bundle state = (Bundle) super.saveState(); // superclass uses a Bundle 2471ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (state == null) { 2481ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang state = new Bundle(); 2491ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 2501ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang state.putBoolean(BUNDLE_DETACHED_MODE, mDetachedMode); 2511ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return state; 252632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 253632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 254632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 255632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void restoreState(Parcelable state, ClassLoader loader) { 2561ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.restoreState. this=%s", this); 257632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.restoreState(state, loader); 2581ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (state != null) { 2591ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang Bundle b = (Bundle) state; 2601ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang b.setClassLoader(loader); 2611ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mDetachedMode = b.getBoolean(BUNDLE_DETACHED_MODE); 2621ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 263632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 264632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 265632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 266632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void startUpdate(ViewGroup container) { 267632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mSafeToNotify = false; 268632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.startUpdate(container); 269632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 270632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 271632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 272632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void finishUpdate(ViewGroup container) { 273632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.finishUpdate(container); 274632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mSafeToNotify = true; 275632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 276632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 277632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 278632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void notifyDataSetChanged() { 279632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (!mSafeToNotify) { 280632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN PagerAdapter.notifyDataSetChanged, ignoring unsafe update"); 281632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return; 282632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 2831ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 284a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // If we are in detached mode, changes to the cursor are of no interest to us, but they may 285a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal // be to parent classes. 286a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal 2871ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // when the currently visible item disappears from the dataset: 2881ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // if the new version of the currently visible item has zero messages: 2891ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // notify the list controller so it can handle this 'current conversation gone' case 2901ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // (by backing out of conversation mode) 2911ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // else 2921ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // 'detach' the conversation view from the cursor, keeping the current item as-is but 2931ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // disabling swipe (effectively the same as singleton mode) 294a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal if (mController != null && !mDetachedMode) { 2951ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang final Conversation currConversation = mController.getCurrentConversation(); 2961ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang final int pos = getConversationPosition(currConversation); 297631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal final Cursor cursor = getCursor(); 298631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal if (pos == POSITION_NONE && cursor != null && currConversation != null) { 2991ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // enable detached mode and do no more here. the fragment itself will figure out 3001ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang // if the conversation is empty (using message list cursor) and back out if needed. 3011ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang mDetachedMode = true; 302a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal mController.setDetachedMode(); 3031ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang LogUtils.i(LOG_TAG, "CPA: current conv is gone, reverting to detached mode. c=%s", 3041ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang currConversation.uri); 30518176786f320b4d4312ad1682da057434f201c13Scott Kennedy 30618176786f320b4d4312ad1682da057434f201c13Scott Kennedy ((AbstractConversationViewFragment) getFragmentAt(mPager.getCurrentItem())) 30718176786f320b4d4312ad1682da057434f201c13Scott Kennedy .onDetachedModeEntered(); 30836280f3c2939bb2dacb4077bd528900346ff4bb9mindyp } else { 309631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal // notify unaffected fragment items of the change, so they can re-render 310631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal // (the change may have been to the labels for a single conversation, for example) 311631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal final AbstractConversationViewFragment frag = (cursor == null) ? null : 31226d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp (AbstractConversationViewFragment) getFragmentAt(pos); 3139d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang if (frag != null && cursor.moveToPosition(pos) && frag.isUserVisible()) { 31416982472f8431aecfdb5f32aa7a97dce9064ac22mindyp // reload what we think is in the current position. 315631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal final Conversation conv = new Conversation(cursor); 316a825aae102a6112a0b4395eb3c5417c7b0c24262mindyp conv.position = pos; 317b2b98ba97983f225eec19dc9bc5333e6ef80ee15mindyp frag.onConversationUpdated(conv); 318b2b98ba97983f225eec19dc9bc5333e6ef80ee15mindyp mController.setCurrentConversation(conv); 31916982472f8431aecfdb5f32aa7a97dce9064ac22mindyp } 3201ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 3211ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 3221ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 323632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.notifyDataSetChanged(); 324632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 325632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 326632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 327632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void setItemVisible(Fragment item, boolean visible) { 328632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang super.setItemVisible(item, visible); 329f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp final AbstractConversationViewFragment fragment = (AbstractConversationViewFragment) item; 330632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang fragment.setExtraUserVisibleHint(visible); 331632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 332632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 3331ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang private Conversation getDefaultConversation() { 3341ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang Conversation c = (mController != null) ? mController.getCurrentConversation() : null; 3351ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (c == null) { 3361ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang c = mInitialConversation; 3371ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 3381ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang return c; 3391ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang } 3401ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang 341632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public int getConversationPosition(Conversation conv) { 3425440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal final ConversationCursor cursor = getCursor(); 3435440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal if (isPagingDisabled(cursor)) { 3441ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang if (conv != getDefaultConversation()) { 34549e0e991fe8880852b936a0f8d7d57c5b36f2154Vikram Aggarwal LogUtils.d(LOG_TAG, "unable to find conversation in singleton mode. c=%s", conv); 346632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return POSITION_NONE; 347632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 348632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return 0; 349632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 350632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 3515440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal // cursor is guaranteed to be non-null because isPagingDisabled() above checks for null 3525440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal // cursor. 3535440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal if (conv == null) { 3548775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang return POSITION_NONE; 3558775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang } 356e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang 357ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang int result = POSITION_NONE; 358c8f2a3c6755b3b78af810aa73ab78487567cf074Paul Westbrook final int pos = cursor.getConversationPosition(conv.id); 359c8f2a3c6755b3b78af810aa73ab78487567cf074Paul Westbrook if (pos >= 0) { 360c8f2a3c6755b3b78af810aa73ab78487567cf074Paul Westbrook LogUtils.d(LOG_TAG, "pager adapter found repositioned convo '%s' at pos=%d", 361c8f2a3c6755b3b78af810aa73ab78487567cf074Paul Westbrook conv.subject, pos); 362c8f2a3c6755b3b78af810aa73ab78487567cf074Paul Westbrook result = pos; 363ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang } 364ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang 365ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang return result; 366632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 367632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 36822ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang public void setPager(ViewPager pager) { 3697d64612104fd861474a09994f13768360f92041dAndy Huang if (mPager != null) { 3707d64612104fd861474a09994f13768360f92041dAndy Huang mPager.setOnPageChangeListener(null); 3717d64612104fd861474a09994f13768360f92041dAndy Huang } 37222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mPager = pager; 3737d64612104fd861474a09994f13768360f92041dAndy Huang if (mPager != null) { 3747d64612104fd861474a09994f13768360f92041dAndy Huang mPager.setOnPageChangeListener(this); 3757d64612104fd861474a09994f13768360f92041dAndy Huang } 37622ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang } 37722ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang 378090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public void setActivityController(ActivityController controller) { 379090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (mController != null) { 380090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mController.unregisterConversationListObserver(mListObserver); 381860164409d7f9e4f726ed4edb2ed77afc6873ad5Andy Huang mController.unregisterFolderObserver(mFolderObserver); 382632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 383090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mController = controller; 384090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang if (mController != null) { 385090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mController.registerConversationListObserver(mListObserver); 386860164409d7f9e4f726ed4edb2ed77afc6873ad5Andy Huang mController.registerFolderObserver(mFolderObserver); 387632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 388e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang notifyDataSetChanged(); 389632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } else { 390e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang // We're being torn down; do not notify. 391e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang // Let the pager controller manage pager lifecycle. 392632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 393632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 394632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 3957d64612104fd861474a09994f13768360f92041dAndy Huang @Override 3967d64612104fd861474a09994f13768360f92041dAndy Huang public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 3977d64612104fd861474a09994f13768360f92041dAndy Huang // no-op 3987d64612104fd861474a09994f13768360f92041dAndy Huang } 3997d64612104fd861474a09994f13768360f92041dAndy Huang 4007d64612104fd861474a09994f13768360f92041dAndy Huang @Override 4017d64612104fd861474a09994f13768360f92041dAndy Huang public void onPageSelected(int position) { 40266db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal if (mController == null) { 40366db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal return; 40466db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal } 40566db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal final Cursor cursor = getCursor(); 40666db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal if (cursor == null || !cursor.moveToPosition(position)) { 40766db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal // No valid cursor or it doesn't have the position we want. Bail. 40866db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal return; 4097d64612104fd861474a09994f13768360f92041dAndy Huang } 41066db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal final Conversation c = new Conversation(cursor); 41166db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal c.position = position; 41266db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal LogUtils.d(LOG_TAG, "pager adapter setting current conv: %s", c.subject); 41366db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal mController.setCurrentConversation(c); 4147d64612104fd861474a09994f13768360f92041dAndy Huang } 4157d64612104fd861474a09994f13768360f92041dAndy Huang 4167d64612104fd861474a09994f13768360f92041dAndy Huang @Override 4177d64612104fd861474a09994f13768360f92041dAndy Huang public void onPageScrollStateChanged(int state) { 4187d64612104fd861474a09994f13768360f92041dAndy Huang // no-op 4197d64612104fd861474a09994f13768360f92041dAndy Huang } 4207d64612104fd861474a09994f13768360f92041dAndy Huang 421090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang // update the pager title strip as the Folder's conversation count changes 422090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang private class FolderObserver extends DataSetObserver { 423090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang @Override 424090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang public void onChanged() { 425090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang notifyDataSetChanged(); 426090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 427090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang } 428090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang 429632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // update the pager dataset as the Controller's cursor changes 430632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private class ListObserver extends DataSetObserver { 431632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 432632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onChanged() { 433e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang notifyDataSetChanged(); 434632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 435632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang @Override 436632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onInvalidated() { 437632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 438632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 439632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 440632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang} 441