ConversationPagerAdapter.java revision 983a723931447b6261a2e42b25e6f931dba6de33
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;
3450ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwalimport com.android.mail.providers.FolderObserver;
35632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.UIProvider;
36f4fce1227d8b49f45e6569f1590565f2df9e8d6emindypimport com.android.mail.ui.AbstractConversationViewFragment;
37090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huangimport com.android.mail.ui.ActivityController;
38632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.ui.ConversationViewFragment;
39351ad4e87e0b0b98df9ca88266a8a63541dc5a81Andy Huangimport com.android.mail.ui.SecureConversationViewFragment;
40632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.utils.FragmentStatePagerAdapter2;
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();
4750ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal    private final FolderObserver mFolderObserver = new FolderObserver() {
4850ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal        @Override
4950ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal        public void onChanged(Folder newFolder) {
5050ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal            notifyDataSetChanged();
5150ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal        }
5250ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal    };
53090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang    private ActivityController mController;
54632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    private final Bundle mCommonFragmentArgs;
55632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    private final Conversation mInitialConversation;
56b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang    private final Account mAccount;
57b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang    private final Folder mFolder;
58632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    /**
59632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     * In singleton mode, this adapter ignores the cursor contents and size, and acts as if the
601ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang     * data set size is exactly size=1, with {@link #getDefaultConversation()} at position 0.
61632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     */
62d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang    private boolean mSingletonMode = false;
63632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    /**
641ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang     * Similar to singleton mode, but once enabled, detached mode is permanent for this adapter.
651ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang     */
661ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang    private boolean mDetachedMode = false;
671ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang    /**
68d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang     * True iff we are in the process of handling a dataset change.
69632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     */
70d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang    private boolean mInDataSetChange = false;
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;
85f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp    private boolean mSanitizedHtml;
86632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
872821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang    private boolean mStopListeningMode = false;
882821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang
892821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang    /**
902821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * After {@link #stopListening()} is called, this contains the last-known count of this adapter.
912821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * We keep this around and use it in lieu of the Cursor's true count until imminent destruction
922821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * to satisfy two opposing requirements:
932821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * <ol>
942821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * <li>The ViewPager always likes to know about all dataset changes via notifyDatasetChanged.
952821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * <li>Destructive changes during pager destruction (e.g. mode transition from conversation mode
962821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * to list mode) must be ignored, or else ViewPager will shift focus onto a neighboring
972821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * conversation and <b>mark it read</b>.
982821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * </ol>
992821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     *
1002821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     */
1012821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang    private int mLastKnownCount;
1022821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang
103d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang    private static final String LOG_TAG = ConversationPagerController.LOG_TAG;
104632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
1051ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang    private static final String BUNDLE_DETACHED_MODE =
1061ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang            ConversationPagerAdapter.class.getName() + "-detachedmode";
1071ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang
10822ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang    public ConversationPagerAdapter(Resources res, FragmentManager fm, Account account,
10922ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang            Folder folder, Conversation initialConversation) {
110632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        super(fm, false /* enableSavedStates */);
11122ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang        mResources = res;
112f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        mCommonFragmentArgs = AbstractConversationViewFragment.makeBasicArgs(account, folder);
113632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        mInitialConversation = initialConversation;
114b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang        mAccount = account;
115b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang        mFolder = folder;
116f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        mSanitizedHtml = mAccount.supportsCapability
117f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp                (UIProvider.AccountCapabilities.SANITIZED_HTML);
118b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang    }
119b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang
120b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang    public boolean matches(Account account, Folder folder) {
121b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang        return mAccount != null && mFolder != null && mAccount.matches(account)
122b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang                && mFolder.equals(folder);
123632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
124632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
125632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public void setSingletonMode(boolean enabled) {
126632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        if (mSingletonMode != enabled) {
127632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            mSingletonMode = enabled;
128632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            notifyDataSetChanged();
129632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
130632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
131632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
132632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public boolean isSingletonMode() {
1331ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        return mSingletonMode;
1341ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang    }
1351ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang
13677fb5be70d76f22a64850aa7a40f6a9553960e4emindyp    public boolean isDetached() {
13777fb5be70d76f22a64850aa7a40f6a9553960e4emindyp        return mDetachedMode;
13877fb5be70d76f22a64850aa7a40f6a9553960e4emindyp    }
13977fb5be70d76f22a64850aa7a40f6a9553960e4emindyp
1405440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal    /**
1415440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal     * Returns true if singleton mode or detached mode have been enabled, or if the current cursor
1425440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal     * is null.
1435440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal     * @param cursor the current conversation cursor (obtained through {@link #getCursor()}.
1445440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal     * @return
1455440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal     */
1465440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal    public boolean isPagingDisabled(Cursor cursor) {
1475440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        return mSingletonMode || mDetachedMode || cursor == null;
148e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang    }
149e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang
1504de145bb568b6963d374fa0bac199218dc494186Paul Westbrook    private ConversationCursor getCursor() {
151a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal        if (mDetachedMode) {
152a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal            // In detached mode, the pager is decoupled from the cursor. Nothing should rely on the
153a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal            // cursor at this point.
154a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal            return null;
155a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal        }
156090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang        if (mController == null) {
157192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal            // Happens when someone calls setActivityController(null) on us. This is done in
158192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal            // ConversationPagerController.stopListening() to indicate that the Conversation View
159192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal            // is going away *very* soon.
1603825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang            LogUtils.i(LOG_TAG, "Pager adapter has a null controller. If the conversation view"
161192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal                    + " is going away, this is fine.  Otherwise, the state is inconsistent");
1628775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang            return null;
163e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang        }
164e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang
165090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang        return mController.getConversationListCursor();
166632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
167632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
168632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
169632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public Fragment getItem(int position) {
170632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        final Conversation c;
171983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook        final ConversationCursor cursor = getCursor();
172632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
1735440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        if (isPagingDisabled(cursor)) {
174632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            // cursor-less adapter is a size-1 cursor that points to mInitialConversation.
175632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            // sanity-check
176632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            if (position != 0) {
177632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang                LogUtils.wtf(LOG_TAG, "pager cursor is null and position is non-zero: %d",
178632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang                        position);
179632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            }
1801ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang            c = getDefaultConversation();
181c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal            c.position = 0;
182632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        } else {
183e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang            if (!cursor.moveToPosition(position)) {
184632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang                LogUtils.wtf(LOG_TAG, "unable to seek to ConversationCursor pos=%d (%s)", position,
185e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang                        cursor);
186632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang                return null;
187632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            }
188983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook            cursor.notifyUIPositionChange();
189632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            // TODO: switch to something like MessageCursor or AttachmentCursor
190632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            // to re-use these models
191e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang            c = new Conversation(cursor);
192c7694221dfa5cec3f4ae290f2266b081b2639d80Vikram Aggarwal            c.position = position;
193632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
194589dec902e0df9f4a624aa983db7232309d29730Scott Kennedy        final AbstractConversationViewFragment f = getConversationViewFragment(c);
195d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        LogUtils.d(LOG_TAG, "IN PagerAdapter.getItem, frag=%s conv=%s this=%s", f, c, this);
196632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        return f;
197632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
198632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
199f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp    private AbstractConversationViewFragment getConversationViewFragment(Conversation c) {
200f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        if (mSanitizedHtml) {
201f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp            return ConversationViewFragment.newInstance(mCommonFragmentArgs, c);
202f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        } else {
203f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp            return SecureConversationViewFragment.newInstance(mCommonFragmentArgs, c);
204f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        }
205f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp    }
206f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp
207632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
208632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public int getCount() {
2092821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        if (mStopListeningMode) {
2106b81f0c6ac2061edd56ddb620fbbb4e04161f9d1Andy Huang            if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
2116b81f0c6ac2061edd56ddb620fbbb4e04161f9d1Andy Huang                final Cursor cursor = getCursor();
2126b81f0c6ac2061edd56ddb620fbbb4e04161f9d1Andy Huang                LogUtils.d(LOG_TAG,
2136b81f0c6ac2061edd56ddb620fbbb4e04161f9d1Andy Huang                        "IN CPA.getCount stopListeningMode, returning lastKnownCount=%d."
2146b81f0c6ac2061edd56ddb620fbbb4e04161f9d1Andy Huang                        + " cursor=%s real count=%s", mLastKnownCount, cursor,
2156b81f0c6ac2061edd56ddb620fbbb4e04161f9d1Andy Huang                        (cursor != null) ? cursor.getCount() : "N/A");
2166b81f0c6ac2061edd56ddb620fbbb4e04161f9d1Andy Huang            }
2172821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang            return mLastKnownCount;
2182821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        }
2192821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang
2205440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        final Cursor cursor = getCursor();
2215440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        if (isPagingDisabled(cursor)) {
2223825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang            LogUtils.d(LOG_TAG, "IN CPA.getCount, returning 1 (effective singleton). cursor=%s",
2235440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal                    cursor);
2248775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang            return 1;
2258775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang        }
2268775ffa4b8c26965352f6ec284adba3867c651d1Andy Huang        return cursor.getCount();
227632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
228632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
229632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
230632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public int getItemPosition(Object item) {
231f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        if (!(item instanceof AbstractConversationViewFragment)) {
232632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            LogUtils.wtf(LOG_TAG, "getItemPosition received unexpected item: %s", item);
233632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
234632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
235f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        final AbstractConversationViewFragment fragment = (AbstractConversationViewFragment) item;
236632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        return getConversationPosition(fragment.getConversation());
237632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
238632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
239632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
240632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public void setPrimaryItem(ViewGroup container, int position, Object object) {
241632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        LogUtils.d(LOG_TAG, "IN PagerAdapter.setPrimaryItem, pos=%d, frag=%s", position,
242632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang                object);
243632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        super.setPrimaryItem(container, position, object);
244632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
245632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
246632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
247632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public CharSequence getPageTitle(int position) {
24822ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang        final String title;
24922ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang        final int currentPosition = mPager.getCurrentItem();
2505440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        final Cursor cursor = getCursor();
2515440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        if (isPagingDisabled(cursor)) {
25268459a7b3265da5002ff331529f12f6b408c9b03Andy Huang            title = null;
25368459a7b3265da5002ff331529f12f6b408c9b03Andy Huang        } else if (position == currentPosition) {
254090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang            int total = getCount();
255090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang            if (mController != null) {
256090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang                final Folder f = mController.getFolder();
257090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang                if (f != null && f.totalCount > total) {
258090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang                    total = f.totalCount;
259090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang                }
260090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang            }
261090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang            title = mResources.getString(R.string.conversation_count, position + 1, total);
26222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang        } else {
26368459a7b3265da5002ff331529f12f6b408c9b03Andy Huang            title = mResources.getString(position < currentPosition ?
26422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang                    R.string.conversation_newer : R.string.conversation_older);
26522ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang        }
26622ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang        return title;
267632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
268632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
269632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
270632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public Parcelable saveState() {
2711ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        LogUtils.d(LOG_TAG, "IN PagerAdapter.saveState. this=%s", this);
2721ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        Bundle state = (Bundle) super.saveState(); // superclass uses a Bundle
2731ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        if (state == null) {
2741ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang            state = new Bundle();
2751ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        }
2761ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        state.putBoolean(BUNDLE_DETACHED_MODE, mDetachedMode);
2771ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        return state;
278632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
279632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
280632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
281632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public void restoreState(Parcelable state, ClassLoader loader) {
282632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        super.restoreState(state, loader);
2831ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        if (state != null) {
2841ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang            Bundle b = (Bundle) state;
2851ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang            b.setClassLoader(loader);
286d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            final boolean detached = b.getBoolean(BUNDLE_DETACHED_MODE);
287d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            setDetachedMode(detached);
2881ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        }
289d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        LogUtils.d(LOG_TAG, "OUT PagerAdapter.restoreState. this=%s", this);
290632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
291632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
292d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang    private void setDetachedMode(boolean detached) {
293d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        if (mDetachedMode == detached) {
294d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            return;
295d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        }
296d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        mDetachedMode = detached;
297d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        if (mDetachedMode) {
298d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            mController.setDetachedMode();
299d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        }
300d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        notifyDataSetChanged();
301632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
302632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
303632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
304d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang    public String toString() {
305d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        final StringBuilder sb = new StringBuilder(super.toString());
306d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.setLength(sb.length() - 1);
307d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(" detachedMode=");
308d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(mDetachedMode);
309d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(" singletonMode=");
310d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(mSingletonMode);
311d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(" mController=");
312d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(mController);
313d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(" mPager=");
314d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(mPager);
315d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(" mStopListening=");
316d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(mStopListeningMode);
317d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(" mLastKnownCount=");
318d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(mLastKnownCount);
319d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(" cursor=");
320d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append(getCursor());
321d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        sb.append("}");
322d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        return sb.toString();
323632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
324632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
325632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
326632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public void notifyDataSetChanged() {
327d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        if (mInDataSetChange) {
328d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            LogUtils.i(LOG_TAG, "CPA ignoring dataset change generated during dataset change");
329632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            return;
330632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
3311ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang
332d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        mInDataSetChange = true;
333a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal        // If we are in detached mode, changes to the cursor are of no interest to us, but they may
334a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal        // be to parent classes.
335a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal
3361ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        // when the currently visible item disappears from the dataset:
3371ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        //   if the new version of the currently visible item has zero messages:
3381ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        //     notify the list controller so it can handle this 'current conversation gone' case
3391ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        //     (by backing out of conversation mode)
3401ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        //   else
3411ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        //     'detach' the conversation view from the cursor, keeping the current item as-is but
3421ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        //     disabling swipe (effectively the same as singleton mode)
343b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy        if (mController != null && !mDetachedMode && mPager != null) {
3441ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang            final Conversation currConversation = mController.getCurrentConversation();
3451ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang            final int pos = getConversationPosition(currConversation);
346631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal            final Cursor cursor = getCursor();
347631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal            if (pos == POSITION_NONE && cursor != null && currConversation != null) {
3481ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang                // enable detached mode and do no more here. the fragment itself will figure out
3491ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang                // if the conversation is empty (using message list cursor) and back out if needed.
350d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang                setDetachedMode(true);
3511ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang                LogUtils.i(LOG_TAG, "CPA: current conv is gone, reverting to detached mode. c=%s",
3521ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang                        currConversation.uri);
35318176786f320b4d4312ad1682da057434f201c13Scott Kennedy
3540558150910ece60b2d8abf1104338e8ffbb0ea17Scott Kennedy                final int currentItem = mPager.getCurrentItem();
355b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy
356b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy                final AbstractConversationViewFragment fragment =
357b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy                        (AbstractConversationViewFragment) getFragmentAt(currentItem);
358b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy
359b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy                if (fragment != null) {
360b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy                    fragment.onDetachedModeEntered();
361b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy                } else {
362b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy                    LogUtils.e(LOG_TAG,
363b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy                            "CPA: notifyDataSetChanged: fragment null, current item: %d",
364b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy                            currentItem);
365b30604cd52a1bacf4f86626181a3224bafc96b42Scott Kennedy                }
36636280f3c2939bb2dacb4077bd528900346ff4bb9mindyp            } else {
367631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal                // notify unaffected fragment items of the change, so they can re-render
368631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal                // (the change may have been to the labels for a single conversation, for example)
369631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal                final AbstractConversationViewFragment frag = (cursor == null) ? null :
37026d4d2d9c43c499f458808f050ec73ea3c28dec4mindyp                        (AbstractConversationViewFragment) getFragmentAt(pos);
3719d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang                if (frag != null && cursor.moveToPosition(pos) && frag.isUserVisible()) {
37216982472f8431aecfdb5f32aa7a97dce9064ac22mindyp                    // reload what we think is in the current position.
373631abc9c544925fa9c02492382dd567b705bf6feVikram Aggarwal                    final Conversation conv = new Conversation(cursor);
374a825aae102a6112a0b4395eb3c5417c7b0c24262mindyp                    conv.position = pos;
375b2b98ba97983f225eec19dc9bc5333e6ef80ee15mindyp                    frag.onConversationUpdated(conv);
376b2b98ba97983f225eec19dc9bc5333e6ef80ee15mindyp                    mController.setCurrentConversation(conv);
37716982472f8431aecfdb5f32aa7a97dce9064ac22mindyp                }
3781ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang            }
379d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        } else {
380d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            LogUtils.d(LOG_TAG, "in CPA.notifyDataSetChanged, doing nothing. this=%s", this);
3811ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        }
3821ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang
383632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        super.notifyDataSetChanged();
384d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        mInDataSetChange = false;
385632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
386632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
387632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    @Override
388632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public void setItemVisible(Fragment item, boolean visible) {
389632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        super.setItemVisible(item, visible);
390f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        final AbstractConversationViewFragment fragment = (AbstractConversationViewFragment) item;
391632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        fragment.setExtraUserVisibleHint(visible);
392632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
393632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
3941ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang    private Conversation getDefaultConversation() {
3951ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        Conversation c = (mController != null) ? mController.getCurrentConversation() : null;
3961ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        if (c == null) {
3971ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang            c = mInitialConversation;
3981ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        }
3991ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang        return c;
4001ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang    }
4011ee96b2b100546b5b69ad42c5bc3755a4293d1a3Andy Huang
402632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public int getConversationPosition(Conversation conv) {
403d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        if (conv == null) {
404d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            return POSITION_NONE;
405d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        }
406d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang
4075440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        final ConversationCursor cursor = getCursor();
4085440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        if (isPagingDisabled(cursor)) {
409d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            final Conversation def = getDefaultConversation();
410d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            if (!conv.equals(def)) {
411d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang                LogUtils.d(LOG_TAG, "unable to find conversation in singleton mode. c=%s def=%s",
412d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang                        conv, def);
413632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang                return POSITION_NONE;
414632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            }
415d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            LogUtils.d(LOG_TAG, "in CPA.getConversationPosition returning 0, conv=%s this=%s",
416d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang                    conv, this);
417632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            return 0;
418632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
419632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
4205440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        // cursor is guaranteed to be non-null because isPagingDisabled() above checks for null
4215440bf50e6b05e1551b375f797ff4bf8ed3f39ceVikram Aggarwal        // cursor.
422e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang
423ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang        int result = POSITION_NONE;
424c8f2a3c6755b3b78af810aa73ab78487567cf074Paul Westbrook        final int pos = cursor.getConversationPosition(conv.id);
425c8f2a3c6755b3b78af810aa73ab78487567cf074Paul Westbrook        if (pos >= 0) {
4269e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang            LogUtils.d(LOG_TAG, "pager adapter found repositioned convo %s at pos=%d",
4279e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang                    conv, pos);
428c8f2a3c6755b3b78af810aa73ab78487567cf074Paul Westbrook            result = pos;
429ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang        }
430ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang
431d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        LogUtils.d(LOG_TAG, "in CPA.getConversationPosition (normal), conv=%s pos=%s this=%s",
432d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang                conv, result, this);
433ca85441f810fdcdd50d285ac5f0319078050c90dAndy Huang        return result;
434632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
435632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
43622ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang    public void setPager(ViewPager pager) {
4377d64612104fd861474a09994f13768360f92041dAndy Huang        if (mPager != null) {
4387d64612104fd861474a09994f13768360f92041dAndy Huang            mPager.setOnPageChangeListener(null);
4397d64612104fd861474a09994f13768360f92041dAndy Huang        }
44022ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang        mPager = pager;
4417d64612104fd861474a09994f13768360f92041dAndy Huang        if (mPager != null) {
4427d64612104fd861474a09994f13768360f92041dAndy Huang            mPager.setOnPageChangeListener(this);
4437d64612104fd861474a09994f13768360f92041dAndy Huang        }
44422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang    }
44522ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang
446090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang    public void setActivityController(ActivityController controller) {
447d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        boolean wasNull = (mController == null);
4482821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        if (mController != null && !mStopListeningMode) {
449090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang            mController.unregisterConversationListObserver(mListObserver);
450860164409d7f9e4f726ed4edb2ed77afc6873ad5Andy Huang            mController.unregisterFolderObserver(mFolderObserver);
451632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
452090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang        mController = controller;
4532821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        if (mController != null && !mStopListeningMode) {
454090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang            mController.registerConversationListObserver(mListObserver);
45550ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal            mFolderObserver.initialize(mController);
456d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            if (!wasNull) {
457d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang                notifyDataSetChanged();
458d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang            }
459632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        } else {
460e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang            // We're being torn down; do not notify.
461e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang            // Let the pager controller manage pager lifecycle.
462632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
463632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
464632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
4652821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang    /**
4662821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     * See {@link ConversationPagerController#stopListening()}.
4672821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang     */
4682821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang    public void stopListening() {
469647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang        if (mStopListeningMode) {
470647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang            // Do nothing since we're already in stop listening mode.  This avoids repeated
471647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang            // unregister observer calls.
472647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang            return;
473647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang        }
474647aefbb36d4541362495e10e2a328d38ff8d2a2Alice Yang
4752821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        // disable the observer, but save off the current count, in case the Pager asks for it
4762821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        // from now until imminent destruction
4772821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang
4782821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        if (mController != null) {
4792821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang            mController.unregisterConversationListObserver(mListObserver);
48050ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal            mFolderObserver.unregisterAndDestroy();
4812821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        }
4822821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        mLastKnownCount = getCount();
4836b81f0c6ac2061edd56ddb620fbbb4e04161f9d1Andy Huang        mStopListeningMode = true;
484d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        LogUtils.d(LOG_TAG, "CPA.stopListening, this=%s", this);
4852821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang    }
4862821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang
4877d64612104fd861474a09994f13768360f92041dAndy Huang    @Override
4887d64612104fd861474a09994f13768360f92041dAndy Huang    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
4897d64612104fd861474a09994f13768360f92041dAndy Huang        // no-op
4907d64612104fd861474a09994f13768360f92041dAndy Huang    }
4917d64612104fd861474a09994f13768360f92041dAndy Huang
4927d64612104fd861474a09994f13768360f92041dAndy Huang    @Override
4937d64612104fd861474a09994f13768360f92041dAndy Huang    public void onPageSelected(int position) {
49466db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal        if (mController == null) {
49566db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal            return;
49666db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal        }
49766db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal        final Cursor cursor = getCursor();
49866db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal        if (cursor == null || !cursor.moveToPosition(position)) {
49966db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal            // No valid cursor or it doesn't have the position we want. Bail.
50066db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal            return;
5017d64612104fd861474a09994f13768360f92041dAndy Huang        }
50266db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal        final Conversation c = new Conversation(cursor);
50366db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal        c.position = position;
5049e4ca7993213d296043d20fe9cf4e166b5d595e8Andy Huang        LogUtils.d(LOG_TAG, "pager adapter setting current conv: %s", c);
50566db04cd71b5096b4496bf6d9468dd2ef8dc86f9Vikram Aggarwal        mController.setCurrentConversation(c);
5067d64612104fd861474a09994f13768360f92041dAndy Huang    }
5077d64612104fd861474a09994f13768360f92041dAndy Huang
5087d64612104fd861474a09994f13768360f92041dAndy Huang    @Override
5097d64612104fd861474a09994f13768360f92041dAndy Huang    public void onPageScrollStateChanged(int state) {
5107d64612104fd861474a09994f13768360f92041dAndy Huang        // no-op
5117d64612104fd861474a09994f13768360f92041dAndy Huang    }
5127d64612104fd861474a09994f13768360f92041dAndy Huang
513632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    // update the pager dataset as the Controller's cursor changes
514632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    private class ListObserver extends DataSetObserver {
515632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        @Override
516632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        public void onChanged() {
517e3df1ad8e630d7d61b4d68f8328f97dd11448b5dAndy Huang            notifyDataSetChanged();
518632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
519632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        @Override
520632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        public void onInvalidated() {
521632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
522632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
523632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
524632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang}
525