ActionBarContainer.java revision e021e6ed8931a0a8296af182fc9b0c76b64fb0c4
1/* 2 * Copyright (C) 2010 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.internal.widget; 18 19import android.content.Context; 20import android.content.res.TypedArray; 21import android.graphics.Canvas; 22import android.graphics.ColorFilter; 23import android.graphics.drawable.Drawable; 24import android.util.AttributeSet; 25import android.view.ActionMode; 26import android.view.MotionEvent; 27import android.view.View; 28import android.view.ViewGroup; 29import android.widget.FrameLayout; 30 31/** 32 * This class acts as a container for the action bar view and action mode context views. 33 * It applies special styles as needed to help handle animated transitions between them. 34 * @hide 35 */ 36public class ActionBarContainer extends FrameLayout { 37 private boolean mIsTransitioning; 38 private View mTabContainer; 39 private View mActionBarView; 40 41 private Drawable mBackground; 42 private Drawable mStackedBackground; 43 private Drawable mSplitBackground; 44 private boolean mIsSplit; 45 private boolean mIsStacked; 46 private int mHeight; 47 48 public ActionBarContainer(Context context) { 49 this(context, null); 50 } 51 52 public ActionBarContainer(Context context, AttributeSet attrs) { 53 super(context, attrs); 54 55 // Set a transparent background so that we project appropriately. 56 setBackground(new ActionBarBackgroundDrawable()); 57 58 TypedArray a = context.obtainStyledAttributes(attrs, 59 com.android.internal.R.styleable.ActionBar); 60 mBackground = a.getDrawable(com.android.internal.R.styleable.ActionBar_background); 61 mStackedBackground = a.getDrawable( 62 com.android.internal.R.styleable.ActionBar_backgroundStacked); 63 mHeight = a.getDimensionPixelSize(com.android.internal.R.styleable.ActionBar_height, -1); 64 65 if (getId() == com.android.internal.R.id.split_action_bar) { 66 mIsSplit = true; 67 mSplitBackground = a.getDrawable( 68 com.android.internal.R.styleable.ActionBar_backgroundSplit); 69 } 70 a.recycle(); 71 72 setWillNotDraw(mIsSplit ? mSplitBackground == null : 73 mBackground == null && mStackedBackground == null); 74 } 75 76 @Override 77 public void onFinishInflate() { 78 super.onFinishInflate(); 79 mActionBarView = findViewById(com.android.internal.R.id.action_bar); 80 } 81 82 public void setPrimaryBackground(Drawable bg) { 83 if (mBackground != null) { 84 mBackground.setCallback(null); 85 unscheduleDrawable(mBackground); 86 } 87 mBackground = bg; 88 if (bg != null) { 89 bg.setCallback(this); 90 if (mActionBarView != null) { 91 mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(), 92 mActionBarView.getRight(), mActionBarView.getBottom()); 93 } 94 } 95 setWillNotDraw(mIsSplit ? mSplitBackground == null : 96 mBackground == null && mStackedBackground == null); 97 invalidate(); 98 } 99 100 public void setStackedBackground(Drawable bg) { 101 if (mStackedBackground != null) { 102 mStackedBackground.setCallback(null); 103 unscheduleDrawable(mStackedBackground); 104 } 105 mStackedBackground = bg; 106 if (bg != null) { 107 bg.setCallback(this); 108 if ((mIsStacked && mStackedBackground != null)) { 109 mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(), 110 mTabContainer.getRight(), mTabContainer.getBottom()); 111 } 112 } 113 setWillNotDraw(mIsSplit ? mSplitBackground == null : 114 mBackground == null && mStackedBackground == null); 115 invalidate(); 116 } 117 118 public void setSplitBackground(Drawable bg) { 119 if (mSplitBackground != null) { 120 mSplitBackground.setCallback(null); 121 unscheduleDrawable(mSplitBackground); 122 } 123 mSplitBackground = bg; 124 if (bg != null) { 125 bg.setCallback(this); 126 if (mIsSplit && mSplitBackground != null) { 127 mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); 128 } 129 } 130 setWillNotDraw(mIsSplit ? mSplitBackground == null : 131 mBackground == null && mStackedBackground == null); 132 invalidate(); 133 } 134 135 @Override 136 public void setVisibility(int visibility) { 137 super.setVisibility(visibility); 138 final boolean isVisible = visibility == VISIBLE; 139 if (mBackground != null) mBackground.setVisible(isVisible, false); 140 if (mStackedBackground != null) mStackedBackground.setVisible(isVisible, false); 141 if (mSplitBackground != null) mSplitBackground.setVisible(isVisible, false); 142 } 143 144 @Override 145 protected boolean verifyDrawable(Drawable who) { 146 return (who == mBackground && !mIsSplit) || (who == mStackedBackground && mIsStacked) || 147 (who == mSplitBackground && mIsSplit) || super.verifyDrawable(who); 148 } 149 150 @Override 151 protected void drawableStateChanged() { 152 super.drawableStateChanged(); 153 if (mBackground != null && mBackground.isStateful()) { 154 mBackground.setState(getDrawableState()); 155 } 156 if (mStackedBackground != null && mStackedBackground.isStateful()) { 157 mStackedBackground.setState(getDrawableState()); 158 } 159 if (mSplitBackground != null && mSplitBackground.isStateful()) { 160 mSplitBackground.setState(getDrawableState()); 161 } 162 } 163 164 @Override 165 public void jumpDrawablesToCurrentState() { 166 super.jumpDrawablesToCurrentState(); 167 if (mBackground != null) { 168 mBackground.jumpToCurrentState(); 169 } 170 if (mStackedBackground != null) { 171 mStackedBackground.jumpToCurrentState(); 172 } 173 if (mSplitBackground != null) { 174 mSplitBackground.jumpToCurrentState(); 175 } 176 } 177 178 /** 179 * @hide 180 */ 181 @Override 182 public void onResolveDrawables(int layoutDirection) { 183 super.onResolveDrawables(layoutDirection); 184 if (mBackground != null) { 185 mBackground.setLayoutDirection(layoutDirection); 186 } 187 if (mStackedBackground != null) { 188 mStackedBackground.setLayoutDirection(layoutDirection); 189 } 190 if (mSplitBackground != null) { 191 mSplitBackground.setLayoutDirection(layoutDirection); 192 } 193 } 194 195 /** 196 * Set the action bar into a "transitioning" state. While transitioning 197 * the bar will block focus and touch from all of its descendants. This 198 * prevents the user from interacting with the bar while it is animating 199 * in or out. 200 * 201 * @param isTransitioning true if the bar is currently transitioning, false otherwise. 202 */ 203 public void setTransitioning(boolean isTransitioning) { 204 mIsTransitioning = isTransitioning; 205 setDescendantFocusability(isTransitioning ? FOCUS_BLOCK_DESCENDANTS 206 : FOCUS_AFTER_DESCENDANTS); 207 } 208 209 @Override 210 public boolean onInterceptTouchEvent(MotionEvent ev) { 211 return mIsTransitioning || super.onInterceptTouchEvent(ev); 212 } 213 214 @Override 215 public boolean onTouchEvent(MotionEvent ev) { 216 super.onTouchEvent(ev); 217 218 // An action bar always eats touch events. 219 return true; 220 } 221 222 @Override 223 public boolean onHoverEvent(MotionEvent ev) { 224 super.onHoverEvent(ev); 225 226 // An action bar always eats hover events. 227 return true; 228 } 229 230 public void setTabContainer(ScrollingTabContainerView tabView) { 231 if (mTabContainer != null) { 232 removeView(mTabContainer); 233 } 234 mTabContainer = tabView; 235 if (tabView != null) { 236 addView(tabView); 237 final ViewGroup.LayoutParams lp = tabView.getLayoutParams(); 238 lp.width = LayoutParams.MATCH_PARENT; 239 lp.height = LayoutParams.WRAP_CONTENT; 240 tabView.setAllowCollapse(false); 241 } 242 } 243 244 public View getTabContainer() { 245 return mTabContainer; 246 } 247 248 @Override 249 public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) { 250 // No starting an action mode for an action bar child! (Where would it go?) 251 return null; 252 } 253 254 private boolean isCollapsed(View view) { 255 return view == null || view.getVisibility() == GONE || view.getMeasuredHeight() == 0; 256 } 257 258 @Override 259 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 260 if (mActionBarView == null && 261 MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST && mHeight >= 0) { 262 heightMeasureSpec = MeasureSpec.makeMeasureSpec( 263 Math.min(mHeight, MeasureSpec.getSize(heightMeasureSpec)), MeasureSpec.AT_MOST); 264 } 265 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 266 267 if (mActionBarView == null) return; 268 269 final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams(); 270 final int actionBarViewHeight = isCollapsed(mActionBarView) ? 0 : 271 mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; 272 273 if (mTabContainer != null && mTabContainer.getVisibility() != GONE) { 274 final int mode = MeasureSpec.getMode(heightMeasureSpec); 275 if (mode == MeasureSpec.AT_MOST) { 276 final int maxHeight = MeasureSpec.getSize(heightMeasureSpec); 277 setMeasuredDimension(getMeasuredWidth(), 278 Math.min(actionBarViewHeight + mTabContainer.getMeasuredHeight(), 279 maxHeight)); 280 } 281 } 282 } 283 284 @Override 285 public void onLayout(boolean changed, int l, int t, int r, int b) { 286 super.onLayout(changed, l, t, r, b); 287 288 final View tabContainer = mTabContainer; 289 final boolean hasTabs = tabContainer != null && tabContainer.getVisibility() != GONE; 290 291 if (tabContainer != null && tabContainer.getVisibility() != GONE) { 292 final int containerHeight = getMeasuredHeight(); 293 final int tabHeight = tabContainer.getMeasuredHeight(); 294 tabContainer.layout(l, containerHeight - tabHeight, r, containerHeight); 295 } 296 297 boolean needsInvalidate = false; 298 if (mIsSplit) { 299 if (mSplitBackground != null) { 300 mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); 301 needsInvalidate = true; 302 } 303 } else { 304 if (mBackground != null) { 305 mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(), 306 mActionBarView.getRight(), mActionBarView.getBottom()); 307 needsInvalidate = true; 308 } 309 mIsStacked = hasTabs; 310 if (hasTabs && mStackedBackground != null) { 311 mStackedBackground.setBounds(tabContainer.getLeft(), tabContainer.getTop(), 312 tabContainer.getRight(), tabContainer.getBottom()); 313 needsInvalidate = true; 314 } 315 } 316 317 if (needsInvalidate) { 318 invalidate(); 319 } 320 } 321 322 /** 323 * Dummy drawable so that we don't break background display lists and 324 * projection surfaces. 325 */ 326 private class ActionBarBackgroundDrawable extends Drawable { 327 @Override 328 public void draw(Canvas canvas) { 329 if (mIsSplit) { 330 if (mSplitBackground != null) mSplitBackground.draw(canvas); 331 } else { 332 if (mBackground != null) { 333 mBackground.draw(canvas); 334 } 335 if (mStackedBackground != null && mIsStacked) { 336 mStackedBackground.draw(canvas); 337 } 338 } 339 } 340 341 @Override 342 public void setAlpha(int alpha) { 343 } 344 345 @Override 346 public void setColorFilter(ColorFilter cf) { 347 } 348 349 @Override 350 public int getOpacity() { 351 return 0; 352 } 353 } 354} 355