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