AppsCustomizeTabHost.java revision b737ee6ab2dc4938a1b2a574c336af0eab826712
1785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung/* 2785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * Copyright (C) 2011 The Android Open Source Project 3785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * 4785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * Licensed under the Apache License, Version 2.0 (the "License"); 5785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * you may not use this file except in compliance with the License. 6785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * You may obtain a copy of the License at 7785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * 8785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * http://www.apache.org/licenses/LICENSE-2.0 9785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * 10785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * Unless required by applicable law or agreed to in writing, software 11785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * distributed under the License is distributed on an "AS IS" BASIS, 12785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * See the License for the specific language governing permissions and 14785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * limitations under the License. 15785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung */ 16785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 17785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungpackage com.android.launcher2; 18785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 19f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chungimport android.animation.Animator; 20b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chungimport android.animation.AnimatorListenerAdapter; 21f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chungimport android.animation.AnimatorSet; 22b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chungimport android.animation.ObjectAnimator; 23785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.content.Context; 24785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.content.res.Resources; 25785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.util.AttributeSet; 26785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.view.LayoutInflater; 274179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chungimport android.view.MotionEvent; 28785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.view.View; 29785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.view.ViewGroup; 30141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurkaimport android.widget.FrameLayout; 311899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurkaimport android.widget.LinearLayout; 32785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.widget.TabHost; 33faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chungimport android.widget.TabWidget; 34785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport android.widget.TextView; 35785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 36785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungimport com.android.launcher.R; 37785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 38141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurkaimport java.util.ArrayList; 39141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka 40785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chungpublic class AppsCustomizeTabHost extends TabHost implements LauncherTransitionable, 41785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung TabHost.OnTabChangeListener { 42785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung static final String LOG_TAG = "AppsCustomizeTabHost"; 43785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 44785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung private static final String APPS_TAB_TAG = "APPS"; 45785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung private static final String WIDGETS_TAB_TAG = "WIDGETS"; 46785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 47785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung private final LayoutInflater mLayoutInflater; 48f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung private ViewGroup mTabs; 49fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung private ViewGroup mTabsContainer; 504179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung private AppsCustomizePagedView mAppsCustomizePane; 510cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen private boolean mSuppressContentCallback = false; 52141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka private FrameLayout mAnimationBuffer; 531899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka private LinearLayout mContent; 54785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 55c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung private boolean mInTransition; 56c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung private boolean mResetAfterTransition; 571899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka private Animator mLauncherTransition; 58c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung 59785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung public AppsCustomizeTabHost(Context context, AttributeSet attrs) { 60785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung super(context, attrs); 61785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung mLayoutInflater = LayoutInflater.from(context); 62785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 63785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 64f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung /** 655a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung * Convenience methods to select specific tabs. We want to set the content type immediately 665a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view 675a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung * reflects the new content (but doesn't do the animation and logic associated with changing 685a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung * tabs manually). 69f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung */ 705a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung private void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) { 715a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung onTabChangedStart(); 725a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung onTabChangedEnd(type); 735a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung } 7455b6550e37da5df2fda44fc712bc082731f2d8e7Winson Chung void selectAppsTab() { 755a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung setContentTypeImmediate(AppsCustomizePagedView.ContentType.Applications); 7655b6550e37da5df2fda44fc712bc082731f2d8e7Winson Chung setCurrentTabByTag(APPS_TAB_TAG); 7755b6550e37da5df2fda44fc712bc082731f2d8e7Winson Chung } 7855b6550e37da5df2fda44fc712bc082731f2d8e7Winson Chung void selectWidgetsTab() { 795a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung setContentTypeImmediate(AppsCustomizePagedView.ContentType.Widgets); 805a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung setCurrentTabByTag(WIDGETS_TAB_TAG); 815a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung } 8255b6550e37da5df2fda44fc712bc082731f2d8e7Winson Chung 83785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung /** 84785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * Setup the tab host and create all necessary tabs. 85785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung */ 86785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung @Override 87785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung protected void onFinishInflate() { 88785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung // Setup the tab host 89785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung setup(); 90785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 91fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung final ViewGroup tabsContainer = (ViewGroup) findViewById(R.id.tabs_container); 92faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung final TabWidget tabs = (TabWidget) findViewById(com.android.internal.R.id.tabs); 934179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung final AppsCustomizePagedView appsCustomizePane = (AppsCustomizePagedView) 94785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung findViewById(R.id.apps_customize_pane_content); 95f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung mTabs = tabs; 96fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung mTabsContainer = tabsContainer; 974179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung mAppsCustomizePane = appsCustomizePane; 98141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka mAnimationBuffer = (FrameLayout) findViewById(R.id.animation_buffer); 991899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka mContent = (LinearLayout) findViewById(R.id.apps_customize_content); 1004179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung if (tabs == null || mAppsCustomizePane == null) throw new Resources.NotFoundException(); 101785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 102785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung // Configure the tabs content factory to return the same paged view (that we change the 103785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung // content filter on) 104785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung TabContentFactory contentFactory = new TabContentFactory() { 105785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung public View createTabContent(String tag) { 1064179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung return appsCustomizePane; 107785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 108785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung }; 109785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 110785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung // Create the tabs 111785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung TextView tabView; 112d2c1f80aa73bef9d7fb5991ec29ea7a7b2e38f90Winson Chung String label; 113d2c1f80aa73bef9d7fb5991ec29ea7a7b2e38f90Winson Chung label = mContext.getString(R.string.all_apps_button_label); 114785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false); 115d2c1f80aa73bef9d7fb5991ec29ea7a7b2e38f90Winson Chung tabView.setText(label); 116d2c1f80aa73bef9d7fb5991ec29ea7a7b2e38f90Winson Chung tabView.setContentDescription(label); 117785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung addTab(newTabSpec(APPS_TAB_TAG).setIndicator(tabView).setContent(contentFactory)); 118d2c1f80aa73bef9d7fb5991ec29ea7a7b2e38f90Winson Chung label = mContext.getString(R.string.widgets_tab_label); 119785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false); 120d2c1f80aa73bef9d7fb5991ec29ea7a7b2e38f90Winson Chung tabView.setText(label); 121d2c1f80aa73bef9d7fb5991ec29ea7a7b2e38f90Winson Chung tabView.setContentDescription(label); 122785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung addTab(newTabSpec(WIDGETS_TAB_TAG).setIndicator(tabView).setContent(contentFactory)); 123785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung setOnTabChangedListener(this); 124faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung 125faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung // Setup the key listener to jump between the last tab view and the market icon 126faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung AppsCustomizeTabKeyEventListener keyListener = new AppsCustomizeTabKeyEventListener(); 127faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung View lastTab = tabs.getChildTabViewAt(tabs.getTabCount() - 1); 128faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung lastTab.setOnKeyListener(keyListener); 129faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung View shopButton = findViewById(R.id.market_button); 130faa13255de0fb1d581ec7a583ed6ef0b661dbea0Winson Chung shopButton.setOnKeyListener(keyListener); 131fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung 132fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung // Hide the tab bar until we measure 133fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung mTabsContainer.setAlpha(0f); 134f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung } 135785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 136f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung @Override 137f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 138f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung boolean remeasureTabWidth = (mTabs.getLayoutParams().width <= 0); 139f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung super.onMeasure(widthMeasureSpec, heightMeasureSpec); 140f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung 141f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung // Set the width of the tab list to the content width 142f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung if (remeasureTabWidth) { 143fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung int contentWidth = mAppsCustomizePane.getPageContentWidth(); 144141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka if (contentWidth > 0 && mTabs.getLayoutParams().width != contentWidth) { 145141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka // Set the width and show the tab bar 146fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung mTabs.getLayoutParams().width = contentWidth; 147c57b7a8233d32c6dd8de5057c570afe3f50e3ef2Michael Jurka post(new Runnable() { 148c57b7a8233d32c6dd8de5057c570afe3f50e3ef2Michael Jurka public void run() { 149c57b7a8233d32c6dd8de5057c570afe3f50e3ef2Michael Jurka mTabs.requestLayout(); 1507ed3774638133ac603e92ca3174ecdd151269ccaWinson Chung mTabsContainer.setAlpha(1f); 151c57b7a8233d32c6dd8de5057c570afe3f50e3ef2Michael Jurka } 152c57b7a8233d32c6dd8de5057c570afe3f50e3ef2Michael Jurka }); 153fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung } 154f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung } 155fd3385fe9e0f034b04f99d5d59a58d74fe040da4Winson Chung super.onMeasure(widthMeasureSpec, heightMeasureSpec); 1564179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung } 1574179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung 1584179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung @Override 1594179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung public boolean onTouchEvent(MotionEvent event) { 1604179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung // Intercept all touch events up to the bottom of the AppsCustomizePane so they do not fall 1614179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung // through to the workspace and trigger showWorkspace() 1624179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung if (event.getY() < mAppsCustomizePane.getBottom()) { 1634179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung return true; 1644179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung } 1654179b4e048dd019daca053dc3a7eddf6c464b08bWinson Chung return super.onTouchEvent(event); 166785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 167785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 1685a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung private void onTabChangedStart() { 1695a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung mAppsCustomizePane.hideScrollingIndicator(false); 1705a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung } 1710cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen 172097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung private void reloadCurrentPage() { 173097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung if (!LauncherApplication.isScreenLarge()) { 174b737ee6ab2dc4938a1b2a574c336af0eab826712Michael Jurka mAppsCustomizePane.flashScrollingIndicator(true); 175097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung } 176097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung mAppsCustomizePane.loadAssociatedPages(mAppsCustomizePane.getCurrentPage()); 177097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung mAppsCustomizePane.requestFocus(); 178097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung } 179097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung 1805a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung private void onTabChangedEnd(AppsCustomizePagedView.ContentType type) { 1815a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung mAppsCustomizePane.setContentType(type); 1825a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung } 1835a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung 184785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung @Override 185785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung public void onTabChanged(String tabId) { 186b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung final AppsCustomizePagedView.ContentType type = getContentTypeForTabTag(tabId); 1870cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen if (mSuppressContentCallback) { 1880cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen mSuppressContentCallback = false; 1890cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen return; 190b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung } 191b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung 1920cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen // Animate the changing of the tab content by fading pages in and out 1930cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen final Resources res = getResources(); 1940cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen final int duration = res.getInteger(R.integer.config_tabTransitionDuration); 195f314b0eab03bb354c14b6c89f694a6685bd246d9Winson Chung 1960cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen // We post a runnable here because there is a delay while the first page is loading and 1970cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen // the feedback from having changed the tab almost feels better than having it stick 1980cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen post(new Runnable() { 1990cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen @Override 2000cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen public void run() { 201097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung if (mAppsCustomizePane.getMeasuredWidth() <= 0 || 202097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung mAppsCustomizePane.getMeasuredHeight() <= 0) { 203097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung reloadCurrentPage(); 204097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung return; 205097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung } 206097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung 207141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka // Take the visible pages and re-parent them temporarily to mAnimatorBuffer 208141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka // and then cross fade to the new pages 209c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung int[] visiblePageRange = new int[2]; 210c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung mAppsCustomizePane.getVisiblePages(visiblePageRange); 211c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung if (visiblePageRange[0] == -1 && visiblePageRange[1] == -1) { 212c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung // If we can't get the visible page ranges, then just skip the animation 213c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung reloadCurrentPage(); 214c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung return; 215c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung } 216c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung ArrayList<View> visiblePages = new ArrayList<View>(); 217c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung for (int i = visiblePageRange[0]; i <= visiblePageRange[1]; i++) { 218c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung visiblePages.add(mAppsCustomizePane.getPageAt(i)); 219c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung } 220141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka 221141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka // We want the pages to be rendered in exactly the same way as they were when 222141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka // their parent was mAppsCustomizePane -- so set the scroll on mAnimationBuffer 223141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka // to be exactly the same as mAppsCustomizePane, and below, set the left/top 224141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka // parameters to be correct for each of the pages 225141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka mAnimationBuffer.scrollTo(mAppsCustomizePane.getScrollX(), 0); 226141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka 227141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka // mAppsCustomizePane renders its children in reverse order, so 228141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka // add the pages to mAnimationBuffer in reverse order to match that behavior 229141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka for (int i = visiblePages.size() - 1; i >= 0; i--) { 230141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka View child = visiblePages.get(i); 231c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung if (child instanceof PagedViewCellLayout) { 232c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung ((PagedViewCellLayout) child).resetChildrenOnKeyListeners(); 233c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung } else if (child instanceof PagedViewGridLayout) { 234c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung ((PagedViewGridLayout) child).resetChildrenOnKeyListeners(); 235c6f10b906fc9c120cafc81046a42b2434ff635a9Winson Chung } 236141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka PagedViewWidget.setDeletePreviewsWhenDetachedFromWindow(false); 237141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka mAppsCustomizePane.removeView(child); 238141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka PagedViewWidget.setDeletePreviewsWhenDetachedFromWindow(true); 239141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka mAnimationBuffer.setAlpha(1f); 240141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka mAnimationBuffer.setVisibility(View.VISIBLE); 241141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka LayoutParams p = new FrameLayout.LayoutParams(child.getWidth(), 242141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka child.getHeight()); 243141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka p.setMargins((int) child.getLeft(), (int) child.getTop(), 0, 0); 244141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka mAnimationBuffer.addView(child, p); 245141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka } 246b44b52439d155f570db7d6d0b80fdd3350e35685Winson Chung 2470cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen // Toggle the new content 2480cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen onTabChangedStart(); 2490cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen onTabChangedEnd(type); 2500cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen 2510cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen // Animate the transition 2520cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen ObjectAnimator outAnim = ObjectAnimator.ofFloat(mAnimationBuffer, "alpha", 0f); 2530cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen outAnim.addListener(new AnimatorListenerAdapter() { 2540cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen @Override 2550cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen public void onAnimationEnd(Animator animation) { 2560cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen mAnimationBuffer.setVisibility(View.GONE); 257141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka mAnimationBuffer.removeAllViews(); 258141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka } 259141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka @Override 260141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka public void onAnimationCancel(Animator animation) { 261141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka mAnimationBuffer.setVisibility(View.GONE); 262141dbd0e02f9fd9f3a096722d8d812990b5931e1Michael Jurka mAnimationBuffer.removeAllViews(); 2630cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen } 2640cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen }); 2650cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen ObjectAnimator inAnim = ObjectAnimator.ofFloat(mAppsCustomizePane, "alpha", 1f); 2660cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen inAnim.addListener(new AnimatorListenerAdapter() { 2670cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen @Override 2680cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen public void onAnimationEnd(Animator animation) { 269097e6c71b12ad1fdc9beba5f74c466521508df9dWinson Chung reloadCurrentPage(); 2700cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen } 2710cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen }); 2720cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen AnimatorSet animSet = new AnimatorSet(); 2730cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen animSet.playTogether(outAnim, inAnim); 2740cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen animSet.setDuration(duration); 2750cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen animSet.start(); 2760cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen } 2770cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen }); 2780cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen } 2790cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen 2800cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) { 2810cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen mSuppressContentCallback = true; 2820cd3b64e607cc1f81ed49b00ef7398c2a2b7a48dAdam Cohen setCurrentTabByTag(getTabTagForContentType(type)); 283785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 284785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 285785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung /** 286785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * Returns the content type for the specified tab tag. 287785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung */ 288785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) { 289785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung if (tag.equals(APPS_TAB_TAG)) { 290785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung return AppsCustomizePagedView.ContentType.Applications; 291785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } else if (tag.equals(WIDGETS_TAB_TAG)) { 292785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung return AppsCustomizePagedView.ContentType.Widgets; 293785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 294785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung return AppsCustomizePagedView.ContentType.Applications; 295785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 296785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 297785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung /** 298fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung * Returns the tab tag for a given content type. 299fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung */ 300fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) { 301fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung if (type == AppsCustomizePagedView.ContentType.Applications) { 302fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung return APPS_TAB_TAG; 303fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung } else if (type == AppsCustomizePagedView.ContentType.Widgets) { 304fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung return WIDGETS_TAB_TAG; 305fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung } 306fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung return APPS_TAB_TAG; 307fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung } 308fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung 309fc79c8067e21e55fce3802a63e15ee4c6f11d595Winson Chung /** 310785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung * Disable focus on anything under this view in the hierarchy if we are not visible. 311785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung */ 312785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung @Override 313785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung public int getDescendantFocusability() { 314785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung if (getVisibility() != View.VISIBLE) { 315785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung return ViewGroup.FOCUS_BLOCK_DESCENDANTS; 316785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 317785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung return super.getDescendantFocusability(); 318785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 319785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung 320c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung void reset() { 321c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung if (mInTransition) { 322c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung // Defer to after the transition to reset 323c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung mResetAfterTransition = true; 324c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung } else { 325c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung // Reset immediately 326c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung mAppsCustomizePane.reset(); 327c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung } 328c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung } 329c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung 3301899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka private void enableAndBuildHardwareLayer() { 33119e0fc53c43a7746d7ae3d7c6027166bded33f0fMichael Jurka // isHardwareAccelerated() checks if we're attached to a window and if that 33219e0fc53c43a7746d7ae3d7c6027166bded33f0fMichael Jurka // window is HW accelerated-- we were sometimes not attached to a window 33319e0fc53c43a7746d7ae3d7c6027166bded33f0fMichael Jurka // and buildLayer was throwing an IllegalStateException 3341899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka if (isHardwareAccelerated()) { 335f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung // Turn on hardware layers for performance 336f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung setLayerType(LAYER_TYPE_HARDWARE, null); 337f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung 3381899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka // force building the layer, so you don't get a blip early in an animation 3391899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka // when the layer is created layer 340f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung buildLayer(); 341f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung } 3421899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka } 3431899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka 3441899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 3451899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka super.onLayout(changed, left, top, right, bottom); 3461899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka if (mLauncherTransition != null) { 3471899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka enableAndBuildHardwareLayer(); 3481899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka mLauncherTransition.start(); 3491899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka mLauncherTransition = null; 3501899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka } 3511899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka } 3521899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka 3531899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka /* LauncherTransitionable overrides */ 3541899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka @Override 3551899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka public boolean onLauncherTransitionStart(Launcher l, Animator animation, boolean toWorkspace) { 3561899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka mInTransition = true; 3571899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka boolean delayLauncherTransitionUntilLayout = false; 3581899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka mLauncherTransition = null; 3591899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka 3601899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka // if the content wasn't visible before, delay the launcher animation until after a cal 3611899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka // to layout -- this prevents a blip 3621899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka if (animation != null) { 3631899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka if (mContent.getVisibility() == GONE) { 3641899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka mLauncherTransition = animation; 3651899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka delayLauncherTransitionUntilLayout = true; 3661899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka } 3671899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka mContent.setVisibility(VISIBLE); 3681899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka if (!delayLauncherTransitionUntilLayout) { 3691899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka enableAndBuildHardwareLayer(); 3701899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka } 3711899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka } 3721899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka 373430e8a5f5b06181addfd37223518fc21c5c41b69Michael Jurka if (!toWorkspace && !LauncherApplication.isScreenLarge()) { 374430e8a5f5b06181addfd37223518fc21c5c41b69Michael Jurka mAppsCustomizePane.showScrollingIndicator(false); 375430e8a5f5b06181addfd37223518fc21c5c41b69Michael Jurka } 376c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung if (mResetAfterTransition) { 377c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung mAppsCustomizePane.reset(); 378c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung mResetAfterTransition = false; 379c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung } 3801899a36ab3aab7671420511f47eb8b273b9b1078Michael Jurka return delayLauncherTransitionUntilLayout; 381785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 382f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung 383785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung @Override 3847d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung public void onLauncherTransitionEnd(Launcher l, Animator animation, boolean toWorkspace) { 385c100e8eae7d67ad5bd78767494b62b8fae5d1779Winson Chung mInTransition = false; 386f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung if (animation != null) { 387f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung setLayerType(LAYER_TYPE_NONE, null); 388f0ea4d3378be7b962c8e0bce2392df5e82491fb8Winson Chung } 3893ac74c55cf8baef29db80e8c67ab4ab033b04417Winson Chung 3907d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung if (!toWorkspace) { 3917d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung // Dismiss the cling if necessary 3927d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung l.dismissWorkspaceCling(null); 3937d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung 3947d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung if (!LauncherApplication.isScreenLarge()) { 3957d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung mAppsCustomizePane.hideScrollingIndicator(false); 3967d7541e7b48fdc114c24b3b0aa75e70d7228041eWinson Chung } 3975a808358f1a773dab8babae44899ffd4ed1810c1Winson Chung } 398785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung } 39970d721061536e0634f6cfa8cd219759a83befceeWinson Chung 40070d721061536e0634f6cfa8cd219759a83befceeWinson Chung boolean isTransitioning() { 40170d721061536e0634f6cfa8cd219759a83befceeWinson Chung return mInTransition; 40270d721061536e0634f6cfa8cd219759a83befceeWinson Chung } 403785d2eb2b8d7072c8124300dd9168ff51a91cf38Winson Chung} 404