ConversationPagerController.java revision 87cf662c9c6c87e7f40dab6545c41484a7e7bfd3
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 205895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huangimport android.app.Fragment; 21632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.app.FragmentManager; 22632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport android.support.v4.view.ViewPager; 235895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huangimport android.support.v4.view.ViewPager.OnPageChangeListener; 2422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huangimport android.view.View; 25632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 26632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.R; 27632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.Account; 28632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.Conversation; 29632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.providers.Folder; 30632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.ui.AbstractActivityController; 315895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huangimport com.android.mail.ui.ActivityController; 32632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.ui.RestrictedActivity; 335895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huangimport com.android.mail.ui.SubjectDisplayChanger; 34b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag; 35632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huangimport com.android.mail.utils.LogUtils; 36632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 37632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang/** 38632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * A simple controller for a {@link ViewPager} of conversations. 39632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * <p> 40632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Instead of placing a ViewPager in a Fragment that replaces the other app views, we leave a 41632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * ViewPager in the activity's view hierarchy at all times and have this controller manage it. 42632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * This allows the ViewPager to safely instantiate inner conversation fragments since it is not 43632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * itself contained in a Fragment (no nested fragments!). 44632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * <p> 45632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * This arrangement has pros and cons...<br> 46632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * pros: FragmentManager manages restoring conversation fragments, each conversation gets its own 47632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * LoaderManager<br> 48632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * cons: the activity's Controller has to specially handle show/hide conversation view, 49632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * conversation fragment transitions must be done manually 50632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * <p> 51632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * This controller is a small delegate of {@link AbstractActivityController} and shares its 52632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * lifetime. 53632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * 54632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 555895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huangpublic class ConversationPagerController implements OnPageChangeListener { 56632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 5722ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang private ViewPager mPager; 58632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private ConversationPagerAdapter mPagerAdapter; 59632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private FragmentManager mFragmentManager; 60090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang private ActivityController mActivityController; 615895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang private SubjectDisplayChanger mSubjectDisplayChanger; 62632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private boolean mShown; 63632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 64b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook private static final String LOG_TAG = LogTag.getLogTag(); 65632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 66632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang /** 67632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Enables an optimization to the PagerAdapter that causes ViewPager to initially load just the 68632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * target conversation, then when the conversation view signals that the conversation is loaded 69632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * and visible (via onConversationSeen), we switch to paged mode to load the left/right 70632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * adjacent conversations. 71632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * <p> 72632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * Should improve load times. It also works around an issue in ViewPager that always loads item 73632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang * zero (with the fragment visibility hint ON) when the adapter is initially set. 74632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang */ 7587cf662c9c6c87e7f40dab6545c41484a7e7bfd3Andy Huang private static final boolean ENABLE_SINGLETON_INITIAL_LOAD = false; 76632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 77632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public ConversationPagerController(RestrictedActivity activity, 785895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang ActivityController controller) { 79632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mFragmentManager = activity.getFragmentManager(); 8022ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mPager = (ViewPager) activity.findViewById(R.id.conversation_pane); 81090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mActivityController = controller; 825895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang mSubjectDisplayChanger = controller.getSubjectDisplayChanger(); 83632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 84632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 85632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void show(Account account, Folder folder, Conversation initialConversation) { 86632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (mShown) { 87632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN CPC.show, but already shown"); 88b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang // optimize for the case where account+folder are the same, when we can just shift 89b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang // the existing pager to show the new conversation 90b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang if (mPagerAdapter != null && mPagerAdapter.matches(account, folder)) { 91b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang final int pos = mPagerAdapter.getConversationPosition(initialConversation); 92b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang if (pos >= 0) { 93b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang mPager.setCurrentItem(pos); 94b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang return; 95b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang } 96b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang } 97b373e3ec0e488914635345627f5734af0f0ef76bAndy Huang // unable to shift, destroy existing state and fall through to normal startup 98632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang cleanup(); 99632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 100632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 10122ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mPager.setVisibility(View.VISIBLE); 10222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang 10322ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mPagerAdapter = new ConversationPagerAdapter(mPager.getResources(), mFragmentManager, 10422ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang account, folder, initialConversation); 105632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPagerAdapter.setSingletonMode(ENABLE_SINGLETON_INITIAL_LOAD); 106090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mPagerAdapter.setActivityController(mActivityController); 10722ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mPagerAdapter.setPager(mPager); 108632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN CPC.show, adapter=%s", mPagerAdapter); 109632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 1105895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang mPager.setOnPageChangeListener(this); 1115895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang 112632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "init pager adapter, count=%d initial=%s", mPagerAdapter.getCount(), 113632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang initialConversation.subject); 114632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPager.setAdapter(mPagerAdapter); 115632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 116632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (!ENABLE_SINGLETON_INITIAL_LOAD) { 117632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // FIXME: unnecessary to do this on restore. setAdapter will restore current position 118632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang final int initialPos = mPagerAdapter.getConversationPosition(initialConversation); 119632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.w(LOG_TAG, "*** pager fragment init pos=%d", initialPos); 120632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPager.setCurrentItem(initialPos); 121632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 122632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 123632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mShown = true; 124632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 125632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 126632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void hide() { 127632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (!mShown) { 128632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN CPC.hide, but already hidden"); 129632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang return; 130632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 131632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mShown = false; 13222ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mPager.setVisibility(View.GONE); 133632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 1345895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang mSubjectDisplayChanger.clearSubject(); 1355895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang 136632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN CPC.hide, clearing adapter and unregistering list observer"); 137632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPager.setAdapter(null); 1385895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang mPager.setOnPageChangeListener(null); 139632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang cleanup(); 140632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 141632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 142632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onDestroy() { 143632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // need to release resources before a configuration change kills the activity and controller 144632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang cleanup(); 145632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 146632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 147632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang private void cleanup() { 148632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang if (mPagerAdapter != null) { 149632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // stop observing the conversation list 150090db1ec6fef366ab9e319040a00eca078ed41c3Andy Huang mPagerAdapter.setActivityController(null); 15122ecc77345c86e0515c1f3c3447502c25c8c53d2Andy Huang mPagerAdapter.setPager(null); 152632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPagerAdapter = null; 153632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 154632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 155632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang 156632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang public void onConversationSeen(Conversation conv) { 157632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // take the adapter out of singleton mode to begin loading the 158632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang // other non-visible conversations 159dd43af4c9b0450350b65bf77fe87f4680b6a786fMindy Pereira if (mPagerAdapter != null && mPagerAdapter.isSingletonMode()) { 160632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang LogUtils.d(LOG_TAG, "IN pager adapter, finished loading primary conversation," + 161632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang " switching to cursor mode to load other conversations"); 162632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang mPagerAdapter.setSingletonMode(false); 163632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 164632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang } 1655895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang 1665895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang @Override 1675895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 1685895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang // no-op 1695895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang } 1705895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang 1715895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang @Override 1725895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang public void onPageSelected(int position) { 1735895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang final Fragment f = mPagerAdapter.getFragmentAt(position); 1745895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang if (f != null) { 1755895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang mPagerAdapter.setItemVisible(f, true); 1765895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang } 1775895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang } 1785895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang 1795895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang @Override 1805895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang public void onPageScrollStateChanged(int state) { 1815895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang // no-op 1825895f7b0e5fa921f6d46bbaf6d8c7b1a8ebc7804Andy Huang } 183192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal 184192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal /** 185192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal * Stops listening to changes to the adapter. This must be followed immediately by 186192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal * {@link #hide()}. 187192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal */ 188192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal public void stopListening() { 189192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal mPagerAdapter.setActivityController(null); 190192fac189e6aed434556a4e37bd3c5c29ef02f29Vikram Aggarwal } 191632721e6b3a9ba8c476456f2e0fb1b564561e0b5Andy Huang} 192