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