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
20f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shahimport android.animation.AnimatorListenerAdapter;
21632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.app.FragmentManager;
22d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huangimport android.content.Context;
23d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huangimport android.content.res.TypedArray;
249d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huangimport android.database.DataSetObservable;
259d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huangimport android.database.DataSetObserver;
26d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huangimport android.graphics.drawable.Drawable;
27632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.support.v4.view.ViewPager;
2822ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huangimport android.view.View;
29f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shahimport android.view.ViewPropertyAnimator;
30632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
31632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.R;
323213ffdac10adb0905cb5440c725345979d4eacfAndrew Sappersteinimport com.android.mail.graphics.PageMarginDrawable;
33632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.Account;
34632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.Conversation;
35632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.Folder;
36632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.ui.AbstractActivityController;
375895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huangimport com.android.mail.ui.ActivityController;
38632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.ui.RestrictedActivity;
39632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.utils.LogUtils;
40243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huangimport com.android.mail.utils.Utils;
41632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
42632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang/**
43632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * A simple controller for a {@link ViewPager} of conversations.
44632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * <p>
45632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Instead of placing a ViewPager in a Fragment that replaces the other app views, we leave a
46632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * ViewPager in the activity's view hierarchy at all times and have this controller manage it.
47632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * This allows the ViewPager to safely instantiate inner conversation fragments since it is not
48632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * itself contained in a Fragment (no nested fragments!).
49632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * <p>
50632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * This arrangement has pros and cons...<br>
51632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * pros: FragmentManager manages restoring conversation fragments, each conversation gets its own
52632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * LoaderManager<br>
53632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * cons: the activity's Controller has to specially handle show/hide conversation view,
54632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * conversation fragment transitions must be done manually
55632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * <p>
56632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * This controller is a small delegate of {@link AbstractActivityController} and shares its
57632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * lifetime.
58632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang *
59632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */
607d64612104fd861474a09994f13768360f92041dAndy Huangpublic class ConversationPagerController {
61632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
6222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang    private ViewPager mPager;
63632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    private ConversationPagerAdapter mPagerAdapter;
64632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    private FragmentManager mFragmentManager;
65090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang    private ActivityController mActivityController;
66632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    private boolean mShown;
679d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang    /**
689d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang     * True when the initial conversation passed to show() is busy loading. We assume that the
6959ccec3db4710f2aea6a4a9a30160ad19331367dAndrew Sapperstein     * first {@link #onConversationSeen()} callback is triggered by that initial
709d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang     * conversation, and unset this flag when first signaled. Side-to-side paging will not re-enable
719d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang     * this flag, since it's only needed for initial conversation load.
729d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang     */
739d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang    private boolean mInitialConversationLoading;
749d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang    private final DataSetObservable mLoadedObservable = new DataSetObservable();
75632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
76d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang    public static final String LOG_TAG = "ConvPager";
77632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
78632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    /**
79632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     * Enables an optimization to the PagerAdapter that causes ViewPager to initially load just the
80632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     * target conversation, then when the conversation view signals that the conversation is loaded
81632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     * and visible (via onConversationSeen), we switch to paged mode to load the left/right
82632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     * adjacent conversations.
83632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     * <p>
84632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     * Should improve load times. It also works around an issue in ViewPager that always loads item
85632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     * zero (with the fragment visibility hint ON) when the adapter is initially set.
86632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang     */
8787cf662c9c6c87e7f40dab6545c41484a7e7bfd3Andy Huang    private static final boolean ENABLE_SINGLETON_INITIAL_LOAD = false;
88632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
89f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah    /** Duration of pager.show(...)'s animation */
90f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah    private static final int SHOW_ANIMATION_DURATION = 300;
91f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah
92632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public ConversationPagerController(RestrictedActivity activity,
935895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang            ActivityController controller) {
94632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        mFragmentManager = activity.getFragmentManager();
95f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang        mPager = (ViewPager) activity.findViewById(R.id.conversation_pager);
96090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang        mActivityController = controller;
97d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang        setupPageMargin(activity.getActivityContext());
98632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
99632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
100f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah    /**
101f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     * Show the conversation pager for the given conversation and animate in if specified along
102f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     * with given animation listener.
103f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     * @param account current account
104f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     * @param folder current folder
105f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     * @param initialConversation conversation to display initially in pager
106f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     * @param changeVisibility true if we need to make the pager appear
10718512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah     * @param pagerAnimationListener animation listener for pager fade-in, null indicates no
10818512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah     *                               animation should take place
109f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     */
110a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang    public void show(Account account, Folder folder, Conversation initialConversation,
111f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah            boolean changeVisibility, AnimatorListenerAdapter pagerAnimationListener) {
1129d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang        mInitialConversationLoading = true;
1139d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang
114632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        if (mShown) {
115632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            LogUtils.d(LOG_TAG, "IN CPC.show, but already shown");
116b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang            // optimize for the case where account+folder are the same, when we can just shift
117b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang            // the existing pager to show the new conversation
11877fb5be70d76f22a64850aa7a40f6a9553960e4emindyp            // If in detached mode, don't do this optimization
11977fb5be70d76f22a64850aa7a40f6a9553960e4emindyp            if (mPagerAdapter != null && mPagerAdapter.matches(account, folder)
12077fb5be70d76f22a64850aa7a40f6a9553960e4emindyp                    && !mPagerAdapter.isDetached()) {
121b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang                final int pos = mPagerAdapter.getConversationPosition(initialConversation);
122b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang                if (pos >= 0) {
12387a8982af83168453b6dc219fe984bff68047bebAndy Huang                    setCurrentItem(pos);
124b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang                    return;
125b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang                }
126b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang            }
127b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang            // unable to shift, destroy existing state and fall through to normal startup
128632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            cleanup();
129632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
130632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
131a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang        if (changeVisibility) {
13218512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah            // If we have a pagerAnimationListener, go ahead and animate
13318512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah            if (pagerAnimationListener != null) {
13418512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                // Reset alpha to 0 before animating/making it visible
13518512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                mPager.setAlpha(0f);
13618512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                mPager.setVisibility(View.VISIBLE);
137f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah
13818512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                // Fade in pager to full visibility - this can be cancelled mid-animation
13918512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                mPager.animate().alpha(1f)
14018512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                        .setDuration(SHOW_ANIMATION_DURATION).setListener(pagerAnimationListener);
141f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah
14218512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah            // Otherwise, make the pager appear without animation
14318512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah            } else {
14418512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                // In case pager animation was cancelled and alpha value was not reset,
14518512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                // ensure that the pager is completely visible for a non-animated pager.show
14618512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                mPager.setAlpha(1f);
14718512bd09af3a5e3d6e8ae2789a40968aa5e8f07Rohan Shah                mPager.setVisibility(View.VISIBLE);
148f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah            }
149a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang        }
15022ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang
151ccf9a34bcdcfdb884799ea3f3ecbd425970f26fcJames Lemieux        mPagerAdapter = new ConversationPagerAdapter(mPager.getContext(), mFragmentManager,
15222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang                account, folder, initialConversation);
153632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        mPagerAdapter.setSingletonMode(ENABLE_SINGLETON_INITIAL_LOAD);
154090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang        mPagerAdapter.setActivityController(mActivityController);
15522ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang        mPagerAdapter.setPager(mPager);
156632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        LogUtils.d(LOG_TAG, "IN CPC.show, adapter=%s", mPagerAdapter);
157632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
158243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang        Utils.sConvLoadTimer.mark("pager init");
159d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang        LogUtils.d(LOG_TAG, "init pager adapter, count=%d initialConv=%s adapter=%s",
160d6ce2fef197dce0f294e5565d9753aac894979dbAndy Huang                mPagerAdapter.getCount(), initialConversation, mPagerAdapter);
161632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        mPager.setAdapter(mPagerAdapter);
162632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
163632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        if (!ENABLE_SINGLETON_INITIAL_LOAD) {
164632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            // FIXME: unnecessary to do this on restore. setAdapter will restore current position
165632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            final int initialPos = mPagerAdapter.getConversationPosition(initialConversation);
1663825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang            if (initialPos >= 0) {
1673825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang                LogUtils.d(LOG_TAG, "*** pager fragment init pos=%d", initialPos);
16887a8982af83168453b6dc219fe984bff68047bebAndy Huang                setCurrentItem(initialPos);
1693825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang            }
170632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
171243c23618b066bcdcd0ab9e36d8c01f50db2cbd0Andy Huang        Utils.sConvLoadTimer.mark("pager setAdapter");
172632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
173632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        mShown = true;
174632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
175632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
176f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah    /**
177f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     * Hide the pager and cancel any running/pending animation
178f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     * @param changeVisibility true if we need to make the pager disappear
179f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah     */
180a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang    public void hide(boolean changeVisibility) {
181632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        if (!mShown) {
182632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            LogUtils.d(LOG_TAG, "IN CPC.hide, but already hidden");
183632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            return;
184632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
185632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        mShown = false;
186f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah
187f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah        // Cancel any potential animations to avoid listener methods running when they shouldn't
188f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah        mPager.animate().cancel();
189f59080ee7ddbb986a295a14578b55f17a10cff4aRohan Shah
190a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang        if (changeVisibility) {
191a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang            mPager.setVisibility(View.GONE);
192a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang        }
193632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
194632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        LogUtils.d(LOG_TAG, "IN CPC.hide, clearing adapter and unregistering list observer");
195632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        mPager.setAdapter(null);
196632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        cleanup();
197632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
198632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
19987a8982af83168453b6dc219fe984bff68047bebAndy Huang    /**
20087a8982af83168453b6dc219fe984bff68047bebAndy Huang     * Part of a delicate dance to kill fragments on restore after rotation if
20187a8982af83168453b6dc219fe984bff68047bebAndy Huang     * the device configuration no longer calls for them. You must call
20287a8982af83168453b6dc219fe984bff68047bebAndy Huang     * {@link #show(Account, Folder, Conversation, boolean, boolean)} first, and you probably want
20387a8982af83168453b6dc219fe984bff68047bebAndy Huang     * to call {@link #hide(boolean)} afterwards to finish the cleanup. See go/xqaxk. Sorry...
20487a8982af83168453b6dc219fe984bff68047bebAndy Huang     *
20587a8982af83168453b6dc219fe984bff68047bebAndy Huang     */
20687a8982af83168453b6dc219fe984bff68047bebAndy Huang    public void killRestoredFragments() {
20787a8982af83168453b6dc219fe984bff68047bebAndy Huang        mPagerAdapter.killRestoredFragments();
20887a8982af83168453b6dc219fe984bff68047bebAndy Huang    }
20987a8982af83168453b6dc219fe984bff68047bebAndy Huang
2100b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao    // Explicitly set the focus to the conversation pager, specifically the conv overlay.
2110b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao    public void focusPager() {
2120b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao        mPager.requestFocus();
2130b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao    }
2140b69338a45faa422ccba8faf64c9816c55d33e4aJin Cao
21587a8982af83168453b6dc219fe984bff68047bebAndy Huang    private void setCurrentItem(int pos) {
21687a8982af83168453b6dc219fe984bff68047bebAndy Huang        // disable onPageSelected notifications during this operation. that listener is only there
21787a8982af83168453b6dc219fe984bff68047bebAndy Huang        // to update the rest of the app when the user swipes to another page.
21887a8982af83168453b6dc219fe984bff68047bebAndy Huang        mPagerAdapter.enablePageChangeListener(false);
21987a8982af83168453b6dc219fe984bff68047bebAndy Huang        mPager.setCurrentItem(pos);
22087a8982af83168453b6dc219fe984bff68047bebAndy Huang        mPagerAdapter.enablePageChangeListener(true);
22187a8982af83168453b6dc219fe984bff68047bebAndy Huang    }
22287a8982af83168453b6dc219fe984bff68047bebAndy Huang
2239d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang    public boolean isInitialConversationLoading() {
2249d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang        return mInitialConversationLoading;
2259d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang    }
2269d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang
227632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    public void onDestroy() {
228632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        // need to release resources before a configuration change kills the activity and controller
229632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        cleanup();
230632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
231632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
232632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    private void cleanup() {
233632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        if (mPagerAdapter != null) {
234632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            // stop observing the conversation list
235090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang            mPagerAdapter.setActivityController(null);
23622ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang            mPagerAdapter.setPager(null);
237632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            mPagerAdapter = null;
238632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
239632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
240632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang
2413b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy    public void onConversationSeen() {
2429d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang        if (mPagerAdapter == null) {
2439d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang            return;
2449d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang        }
2459d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang
246632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        // take the adapter out of singleton mode to begin loading the
247632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        // other non-visible conversations
2489d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang        if (mPagerAdapter.isSingletonMode()) {
2493825f3d2284b2b57fadcfe6a4ebd9992f3c5c7bbAndy Huang            LogUtils.i(LOG_TAG, "IN pager adapter, finished loading primary conversation," +
250632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang                    " switching to cursor mode to load other conversations");
251632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang            mPagerAdapter.setSingletonMode(false);
252632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang        }
2539d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang
2549d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang        if (mInitialConversationLoading) {
2559d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang            mInitialConversationLoading = false;
2569d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang            mLoadedObservable.notifyChanged();
2579d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang        }
2589d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang    }
2599d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang
2609d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang    public void registerConversationLoadedObserver(DataSetObserver observer) {
2619d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang        mLoadedObservable.registerObserver(observer);
2629d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang    }
2639d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang
2649d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang    public void unregisterConversationLoadedObserver(DataSetObserver observer) {
2659d3fd92ed6091dbd0d38799222a1cf841f1c3f29Andy Huang        mLoadedObservable.unregisterObserver(observer);
266632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang    }
2675895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang
268192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal    /**
269192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal     * Stops listening to changes to the adapter. This must be followed immediately by
270a3ed834c959ece3453c1b34953fabecb3b19c424Andy Huang     * {@link #hide(boolean)}.
271192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal     */
272192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal    public void stopListening() {
2732821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        if (mPagerAdapter != null) {
2742821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang            mPagerAdapter.stopListening();
2752821aeaa8c06011d67344a0232079a69bd003ef8Andy Huang        }
276192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal    }
277d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang
278d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang    private void setupPageMargin(Context c) {
279d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang        final TypedArray a = c.obtainStyledAttributes(new int[] {android.R.attr.listDivider});
280d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang        final Drawable divider = a.getDrawable(0);
281d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang        a.recycle();
282d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang        final int padding = c.getResources().getDimensionPixelOffset(
283d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang                R.dimen.conversation_page_gutter);
2843213ffdac10adb0905cb5440c725345979d4eacfAndrew Sapperstein        final Drawable gutterDrawable = new PageMarginDrawable(divider, padding, 0, padding, 0,
285eb58a092961773a8da67c0e0dd5770346381d938Andrew Sapperstein                c.getResources().getColor(R.color.conversation_view_background_color));
286d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang        mPager.setPageMargin(gutterDrawable.getIntrinsicWidth() + 2 * padding);
287d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang        mPager.setPageMarginDrawable(gutterDrawable);
288d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang    }
289d00f346a1b0b1ea3a1029ed95c9beb693b418187Andy Huang
290632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang}
291