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