1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.launcher3;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.AnimatorSet;
22import android.animation.ObjectAnimator;
23import android.content.Context;
24import android.content.res.Resources;
25import android.graphics.Color;
26import android.graphics.Rect;
27import android.util.AttributeSet;
28import android.view.LayoutInflater;
29import android.view.MotionEvent;
30import android.view.View;
31import android.view.ViewGroup;
32import android.view.accessibility.AccessibilityManager;
33import android.widget.FrameLayout;
34import android.widget.LinearLayout;
35import android.widget.TabHost;
36import android.widget.TabWidget;
37import android.widget.TextView;
38
39import java.util.ArrayList;
40
41public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable  {
42    static final String LOG_TAG = "AppsCustomizeTabHost";
43
44    private static final String APPS_TAB_TAG = "APPS";
45    private static final String WIDGETS_TAB_TAG = "WIDGETS";
46
47    private AppsCustomizePagedView mPagedView;
48    private View mContent;
49    private boolean mInTransition = false;
50
51    private final Rect mInsets = new Rect();
52
53    public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
54        super(context, attrs);
55    }
56
57    /**
58     * Convenience methods to select specific tabs.  We want to set the content type immediately
59     * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view
60     * reflects the new content (but doesn't do the animation and logic associated with changing
61     * tabs manually).
62     */
63    void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) {
64        mPagedView.setContentType(type);
65    }
66
67    public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
68        setContentTypeImmediate(type);
69    }
70
71    @Override
72    public void setInsets(Rect insets) {
73        mInsets.set(insets);
74        LayoutParams flp = (LayoutParams) mContent.getLayoutParams();
75        flp.topMargin = insets.top;
76        flp.bottomMargin = insets.bottom;
77        flp.leftMargin = insets.left;
78        flp.rightMargin = insets.right;
79        mContent.setLayoutParams(flp);
80    }
81
82    /**
83     * Setup the tab host and create all necessary tabs.
84     */
85    @Override
86    protected void onFinishInflate() {
87        mPagedView = (AppsCustomizePagedView) findViewById(R.id.apps_customize_pane_content);
88        mContent = findViewById(R.id.content);
89    }
90
91    public String getContentTag() {
92        return getTabTagForContentType(mPagedView.getContentType());
93    }
94
95    /**
96     * Returns the content type for the specified tab tag.
97     */
98    public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
99        if (tag.equals(APPS_TAB_TAG)) {
100            return AppsCustomizePagedView.ContentType.Applications;
101        } else if (tag.equals(WIDGETS_TAB_TAG)) {
102            return AppsCustomizePagedView.ContentType.Widgets;
103        }
104        return AppsCustomizePagedView.ContentType.Applications;
105    }
106
107    /**
108     * Returns the tab tag for a given content type.
109     */
110    public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
111        if (type == AppsCustomizePagedView.ContentType.Applications) {
112            return APPS_TAB_TAG;
113        } else if (type == AppsCustomizePagedView.ContentType.Widgets) {
114            return WIDGETS_TAB_TAG;
115        }
116        return APPS_TAB_TAG;
117    }
118
119    /**
120     * Disable focus on anything under this view in the hierarchy if we are not visible.
121     */
122    @Override
123    public int getDescendantFocusability() {
124        if (getVisibility() != View.VISIBLE) {
125            return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
126        }
127        return super.getDescendantFocusability();
128    }
129
130    void reset() {
131        // Reset immediately
132        mPagedView.reset();
133    }
134
135    public void onWindowVisible() {
136        if (getVisibility() == VISIBLE) {
137            mContent.setVisibility(VISIBLE);
138            // We unload the widget previews when the UI is hidden, so need to reload pages
139            // Load the current page synchronously, and the neighboring pages asynchronously
140            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage(), true);
141            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
142        }
143    }
144
145    public void onTrimMemory() {
146        mContent.setVisibility(GONE);
147        // Clear the widget pages of all their subviews - this will trigger the widget previews
148        // to delete their bitmaps
149        mPagedView.clearAllWidgetPages();
150    }
151
152    @Override
153    public ViewGroup getContent() {
154        return mPagedView;
155    }
156
157    public boolean isInTransition() {
158        return mInTransition;
159    }
160
161    /* LauncherTransitionable overrides */
162    @Override
163    public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
164        mPagedView.onLauncherTransitionPrepare(l, animated, toWorkspace);
165        mInTransition = true;
166
167        if (toWorkspace) {
168            // Going from All Apps -> Workspace
169            setVisibilityOfSiblingsWithLowerZOrder(VISIBLE);
170        } else {
171            // Going from Workspace -> All Apps
172            mContent.setVisibility(VISIBLE);
173
174            // Make sure the current page is loaded (we start loading the side pages after the
175            // transition to prevent slowing down the animation)
176            // TODO: revisit this
177            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
178        }
179    }
180
181    @Override
182    public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
183        mPagedView.onLauncherTransitionStart(l, animated, toWorkspace);
184    }
185
186    @Override
187    public void onLauncherTransitionStep(Launcher l, float t) {
188        mPagedView.onLauncherTransitionStep(l, t);
189    }
190
191    @Override
192    public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
193        mPagedView.onLauncherTransitionEnd(l, animated, toWorkspace);
194        mInTransition = false;
195
196        if (!toWorkspace) {
197            // Make sure adjacent pages are loaded (we wait until after the transition to
198            // prevent slowing down the animation)
199            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
200
201            // Opening apps, need to announce what page we are on.
202            AccessibilityManager am = (AccessibilityManager)
203                    getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
204            if (am.isEnabled()) {
205                // Notify the user when the page changes
206                announceForAccessibility(mPagedView.getCurrentPageDescription());
207            }
208
209            // Going from Workspace -> All Apps
210            // NOTE: We should do this at the end since we check visibility state in some of the
211            // cling initialization/dismiss code above.
212            setVisibilityOfSiblingsWithLowerZOrder(INVISIBLE);
213        }
214    }
215
216    private void setVisibilityOfSiblingsWithLowerZOrder(int visibility) {
217        ViewGroup parent = (ViewGroup) getParent();
218        if (parent == null) return;
219
220        View overviewPanel = ((Launcher) getContext()).getOverviewPanel();
221        final int count = parent.getChildCount();
222        if (!isChildrenDrawingOrderEnabled()) {
223            for (int i = 0; i < count; i++) {
224                final View child = parent.getChildAt(i);
225                if (child == this) {
226                    break;
227                } else {
228                    if (child.getVisibility() == GONE || child == overviewPanel) {
229                        continue;
230                    }
231                    child.setVisibility(visibility);
232                }
233            }
234        } else {
235            throw new RuntimeException("Failed; can't get z-order of views");
236        }
237    }
238}
239