blob: a5efa82df124ea8ba6859ccc1c9de3549c03c68e [file] [log] [blame]
Adam Powell45f1e082010-12-10 14:20:13 -08001/*
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
Chris Craik77b5cad2014-07-30 18:23:07 -070019import android.annotation.NonNull;
Adam Powell45f1e082010-12-10 14:20:13 -080020import android.content.Context;
21import android.content.res.TypedArray;
Adam Powella72ef622011-07-06 22:53:11 -070022import android.graphics.Canvas;
Alan Viverette7f610fe2014-02-19 14:40:12 -080023import android.graphics.ColorFilter;
Chris Craik77b5cad2014-07-30 18:23:07 -070024import android.graphics.Outline;
Adam Powellf849a5e2014-09-11 15:09:36 -070025import android.graphics.PixelFormat;
Adam Powella72ef622011-07-06 22:53:11 -070026import android.graphics.drawable.Drawable;
Adam Powell45f1e082010-12-10 14:20:13 -080027import android.util.AttributeSet;
Adam Powell640a66e2011-04-29 10:18:53 -070028import android.view.ActionMode;
Adam Powell6ecf3d12010-12-19 13:14:58 -080029import android.view.MotionEvent;
Adam Powelldae78242011-04-25 15:23:41 -070030import android.view.View;
Adam Powellaf6b97e2011-08-11 17:40:57 -070031import android.view.ViewGroup;
Adam Powell45f1e082010-12-10 14:20:13 -080032import android.widget.FrameLayout;
33
34/**
35 * This class acts as a container for the action bar view and action mode context views.
36 * It applies special styles as needed to help handle animated transitions between them.
37 * @hide
38 */
39public class ActionBarContainer extends FrameLayout {
Adam Powell01feaee2011-02-10 15:05:05 -080040 private boolean mIsTransitioning;
Adam Powelldae78242011-04-25 15:23:41 -070041 private View mTabContainer;
Adam Powelle021e6e2014-05-23 17:27:24 -070042 private View mActionBarView;
Chet Haaseccd3da22014-09-12 18:03:55 -070043 private View mActionContextView;
Adam Powell01feaee2011-02-10 15:05:05 -080044
Adam Powella72ef622011-07-06 22:53:11 -070045 private Drawable mBackground;
46 private Drawable mStackedBackground;
47 private Drawable mSplitBackground;
48 private boolean mIsSplit;
49 private boolean mIsStacked;
Adam Powelle43340c2014-03-17 19:10:43 -070050 private int mHeight;
Adam Powella72ef622011-07-06 22:53:11 -070051
Adam Powell45f1e082010-12-10 14:20:13 -080052 public ActionBarContainer(Context context) {
53 this(context, null);
54 }
55
56 public ActionBarContainer(Context context, AttributeSet attrs) {
57 super(context, attrs);
58
Alan Viverette7f610fe2014-02-19 14:40:12 -080059 // Set a transparent background so that we project appropriately.
60 setBackground(new ActionBarBackgroundDrawable());
Adam Powella72ef622011-07-06 22:53:11 -070061
Adam Powell45f1e082010-12-10 14:20:13 -080062 TypedArray a = context.obtainStyledAttributes(attrs,
63 com.android.internal.R.styleable.ActionBar);
Adam Powella72ef622011-07-06 22:53:11 -070064 mBackground = a.getDrawable(com.android.internal.R.styleable.ActionBar_background);
65 mStackedBackground = a.getDrawable(
66 com.android.internal.R.styleable.ActionBar_backgroundStacked);
Adam Powelle43340c2014-03-17 19:10:43 -070067 mHeight = a.getDimensionPixelSize(com.android.internal.R.styleable.ActionBar_height, -1);
Adam Powella72ef622011-07-06 22:53:11 -070068
69 if (getId() == com.android.internal.R.id.split_action_bar) {
70 mIsSplit = true;
71 mSplitBackground = a.getDrawable(
72 com.android.internal.R.styleable.ActionBar_backgroundSplit);
73 }
Adam Powell45f1e082010-12-10 14:20:13 -080074 a.recycle();
Adam Powella72ef622011-07-06 22:53:11 -070075
76 setWillNotDraw(mIsSplit ? mSplitBackground == null :
77 mBackground == null && mStackedBackground == null);
Adam Powell45f1e082010-12-10 14:20:13 -080078 }
Adam Powell6ecf3d12010-12-19 13:14:58 -080079
Adam Powell310849a2011-06-08 20:07:17 -070080 @Override
81 public void onFinishInflate() {
82 super.onFinishInflate();
Adam Powelle021e6e2014-05-23 17:27:24 -070083 mActionBarView = findViewById(com.android.internal.R.id.action_bar);
Chet Haaseccd3da22014-09-12 18:03:55 -070084 mActionContextView = findViewById(com.android.internal.R.id.action_context_bar);
Adam Powell310849a2011-06-08 20:07:17 -070085 }
86
Adam Powellf88b9152011-09-07 14:54:32 -070087 public void setPrimaryBackground(Drawable bg) {
Adam Powella7cc06d2012-08-01 16:31:23 -070088 if (mBackground != null) {
89 mBackground.setCallback(null);
90 unscheduleDrawable(mBackground);
91 }
Adam Powellf88b9152011-09-07 14:54:32 -070092 mBackground = bg;
Adam Powella7cc06d2012-08-01 16:31:23 -070093 if (bg != null) {
94 bg.setCallback(this);
Adam Powelle8c8ae42013-02-08 17:32:24 -080095 if (mActionBarView != null) {
96 mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
97 mActionBarView.getRight(), mActionBarView.getBottom());
98 }
Adam Powella7cc06d2012-08-01 16:31:23 -070099 }
100 setWillNotDraw(mIsSplit ? mSplitBackground == null :
101 mBackground == null && mStackedBackground == null);
Adam Powellf88b9152011-09-07 14:54:32 -0700102 invalidate();
103 }
104
105 public void setStackedBackground(Drawable bg) {
Adam Powella7cc06d2012-08-01 16:31:23 -0700106 if (mStackedBackground != null) {
107 mStackedBackground.setCallback(null);
108 unscheduleDrawable(mStackedBackground);
109 }
Adam Powellf88b9152011-09-07 14:54:32 -0700110 mStackedBackground = bg;
Adam Powella7cc06d2012-08-01 16:31:23 -0700111 if (bg != null) {
112 bg.setCallback(this);
Adam Powelle8c8ae42013-02-08 17:32:24 -0800113 if ((mIsStacked && mStackedBackground != null)) {
114 mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(),
115 mTabContainer.getRight(), mTabContainer.getBottom());
116 }
Adam Powella7cc06d2012-08-01 16:31:23 -0700117 }
118 setWillNotDraw(mIsSplit ? mSplitBackground == null :
119 mBackground == null && mStackedBackground == null);
Adam Powellf88b9152011-09-07 14:54:32 -0700120 invalidate();
121 }
122
123 public void setSplitBackground(Drawable bg) {
Adam Powella7cc06d2012-08-01 16:31:23 -0700124 if (mSplitBackground != null) {
125 mSplitBackground.setCallback(null);
126 unscheduleDrawable(mSplitBackground);
127 }
Adam Powellf88b9152011-09-07 14:54:32 -0700128 mSplitBackground = bg;
Adam Powella7cc06d2012-08-01 16:31:23 -0700129 if (bg != null) {
130 bg.setCallback(this);
Adam Powelle8c8ae42013-02-08 17:32:24 -0800131 if (mIsSplit && mSplitBackground != null) {
132 mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
133 }
Adam Powella7cc06d2012-08-01 16:31:23 -0700134 }
135 setWillNotDraw(mIsSplit ? mSplitBackground == null :
136 mBackground == null && mStackedBackground == null);
Adam Powellf88b9152011-09-07 14:54:32 -0700137 invalidate();
138 }
139
Adam Powella7cc06d2012-08-01 16:31:23 -0700140 @Override
141 public void setVisibility(int visibility) {
142 super.setVisibility(visibility);
143 final boolean isVisible = visibility == VISIBLE;
144 if (mBackground != null) mBackground.setVisible(isVisible, false);
145 if (mStackedBackground != null) mStackedBackground.setVisible(isVisible, false);
146 if (mSplitBackground != null) mSplitBackground.setVisible(isVisible, false);
147 }
148
149 @Override
150 protected boolean verifyDrawable(Drawable who) {
151 return (who == mBackground && !mIsSplit) || (who == mStackedBackground && mIsStacked) ||
152 (who == mSplitBackground && mIsSplit) || super.verifyDrawable(who);
153 }
154
155 @Override
156 protected void drawableStateChanged() {
157 super.drawableStateChanged();
158 if (mBackground != null && mBackground.isStateful()) {
159 mBackground.setState(getDrawableState());
160 }
161 if (mStackedBackground != null && mStackedBackground.isStateful()) {
162 mStackedBackground.setState(getDrawableState());
163 }
164 if (mSplitBackground != null && mSplitBackground.isStateful()) {
165 mSplitBackground.setState(getDrawableState());
166 }
167 }
168
169 @Override
170 public void jumpDrawablesToCurrentState() {
171 super.jumpDrawablesToCurrentState();
172 if (mBackground != null) {
173 mBackground.jumpToCurrentState();
174 }
175 if (mStackedBackground != null) {
176 mStackedBackground.jumpToCurrentState();
177 }
178 if (mSplitBackground != null) {
179 mSplitBackground.jumpToCurrentState();
180 }
181 }
182
Fabrice Di Meglio4457e852012-09-18 19:23:12 -0700183 /**
184 * @hide
185 */
Adam Powella7cc06d2012-08-01 16:31:23 -0700186 @Override
187 public void onResolveDrawables(int layoutDirection) {
188 super.onResolveDrawables(layoutDirection);
189 if (mBackground != null) {
190 mBackground.setLayoutDirection(layoutDirection);
191 }
192 if (mStackedBackground != null) {
193 mStackedBackground.setLayoutDirection(layoutDirection);
194 }
195 if (mSplitBackground != null) {
196 mSplitBackground.setLayoutDirection(layoutDirection);
197 }
198 }
199
Adam Powell01feaee2011-02-10 15:05:05 -0800200 /**
201 * Set the action bar into a "transitioning" state. While transitioning
202 * the bar will block focus and touch from all of its descendants. This
203 * prevents the user from interacting with the bar while it is animating
204 * in or out.
205 *
206 * @param isTransitioning true if the bar is currently transitioning, false otherwise.
207 */
208 public void setTransitioning(boolean isTransitioning) {
209 mIsTransitioning = isTransitioning;
210 setDescendantFocusability(isTransitioning ? FOCUS_BLOCK_DESCENDANTS
211 : FOCUS_AFTER_DESCENDANTS);
212 }
213
214 @Override
215 public boolean onInterceptTouchEvent(MotionEvent ev) {
216 return mIsTransitioning || super.onInterceptTouchEvent(ev);
217 }
218
Adam Powell6ecf3d12010-12-19 13:14:58 -0800219 @Override
220 public boolean onTouchEvent(MotionEvent ev) {
221 super.onTouchEvent(ev);
Adam Powelldae78242011-04-25 15:23:41 -0700222
223 // An action bar always eats touch events.
Adam Powell6ecf3d12010-12-19 13:14:58 -0800224 return true;
225 }
Adam Powelldae78242011-04-25 15:23:41 -0700226
Adam Powell7d09f042011-10-10 11:15:56 -0700227 @Override
228 public boolean onHoverEvent(MotionEvent ev) {
229 super.onHoverEvent(ev);
230
231 // An action bar always eats hover events.
232 return true;
233 }
234
Adam Powellf5645cb2011-08-10 22:49:02 -0700235 public void setTabContainer(ScrollingTabContainerView tabView) {
Adam Powelldae78242011-04-25 15:23:41 -0700236 if (mTabContainer != null) {
237 removeView(mTabContainer);
238 }
239 mTabContainer = tabView;
Adam Powell25151e42011-05-26 15:44:59 -0700240 if (tabView != null) {
241 addView(tabView);
Adam Powellaf6b97e2011-08-11 17:40:57 -0700242 final ViewGroup.LayoutParams lp = tabView.getLayoutParams();
243 lp.width = LayoutParams.MATCH_PARENT;
244 lp.height = LayoutParams.WRAP_CONTENT;
Adam Powellf5645cb2011-08-10 22:49:02 -0700245 tabView.setAllowCollapse(false);
Adam Powell25151e42011-05-26 15:44:59 -0700246 }
Adam Powelldae78242011-04-25 15:23:41 -0700247 }
248
249 public View getTabContainer() {
250 return mTabContainer;
251 }
252
253 @Override
Adam Powell640a66e2011-04-29 10:18:53 -0700254 public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
255 // No starting an action mode for an action bar child! (Where would it go?)
256 return null;
257 }
258
Clara Bayarri4423d912015-03-02 19:42:48 +0000259 @Override
260 public ActionMode startActionModeForChild(
261 View child, ActionMode.Callback callback, int type) {
262 if (type != ActionMode.TYPE_PRIMARY) {
263 return super.startActionModeForChild(child, callback, type);
264 }
265 return null;
266 }
267
Chris Craik1e610d42014-08-13 10:37:18 -0700268 private static boolean isCollapsed(View view) {
Adam Powelle021e6e2014-05-23 17:27:24 -0700269 return view == null || view.getVisibility() == GONE || view.getMeasuredHeight() == 0;
270 }
271
Yigit Boyar2bbad0c2014-09-16 18:28:03 -0700272 private int getMeasuredHeightWithMargins(View view) {
273 final LayoutParams lp = (LayoutParams) view.getLayoutParams();
274 return view.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
275 }
276
Adam Powell640a66e2011-04-29 10:18:53 -0700277 @Override
Adam Powelldae78242011-04-25 15:23:41 -0700278 public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Adam Powelle43340c2014-03-17 19:10:43 -0700279 if (mActionBarView == null &&
280 MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST && mHeight >= 0) {
281 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
282 Math.min(mHeight, MeasureSpec.getSize(heightMeasureSpec)), MeasureSpec.AT_MOST);
283 }
Adam Powelldae78242011-04-25 15:23:41 -0700284 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Adam Powelld21aa122011-05-27 13:09:52 -0700285
Adam Powellf6ce6a92011-06-29 10:25:01 -0700286 if (mActionBarView == null) return;
Adam Powell310849a2011-06-08 20:07:17 -0700287
Adam Powelldae78242011-04-25 15:23:41 -0700288 if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
Yigit Boyar2bbad0c2014-09-16 18:28:03 -0700289 int nonTabMaxHeight = 0;
290 final int childCount = getChildCount();
291 for (int i = 0; i < childCount; i++) {
292 final View child = getChildAt(i);
293 if (child == mTabContainer) {
294 continue;
295 }
296 nonTabMaxHeight = Math.max(nonTabMaxHeight, isCollapsed(child) ? 0 :
297 getMeasuredHeightWithMargins(child));
Adam Powelldae78242011-04-25 15:23:41 -0700298 }
Yigit Boyar2bbad0c2014-09-16 18:28:03 -0700299 final int mode = MeasureSpec.getMode(heightMeasureSpec);
300 final int maxHeight = mode == MeasureSpec.AT_MOST ?
301 MeasureSpec.getSize(heightMeasureSpec) : Integer.MAX_VALUE;
302 setMeasuredDimension(getMeasuredWidth(),
303 Math.min(nonTabMaxHeight + getMeasuredHeightWithMargins(mTabContainer),
304 maxHeight));
Adam Powelldae78242011-04-25 15:23:41 -0700305 }
306 }
307
308 @Override
309 public void onLayout(boolean changed, int l, int t, int r, int b) {
310 super.onLayout(changed, l, t, r, b);
Adam Powella72ef622011-07-06 22:53:11 -0700311
Alan Viverette7f610fe2014-02-19 14:40:12 -0800312 final View tabContainer = mTabContainer;
313 final boolean hasTabs = tabContainer != null && tabContainer.getVisibility() != GONE;
Adam Powella72ef622011-07-06 22:53:11 -0700314
Alan Viverette7f610fe2014-02-19 14:40:12 -0800315 if (tabContainer != null && tabContainer.getVisibility() != GONE) {
Adam Powelldae78242011-04-25 15:23:41 -0700316 final int containerHeight = getMeasuredHeight();
Yigit Boyar2bbad0c2014-09-16 18:28:03 -0700317 final LayoutParams lp = (LayoutParams) tabContainer.getLayoutParams();
Alan Viverette7f610fe2014-02-19 14:40:12 -0800318 final int tabHeight = tabContainer.getMeasuredHeight();
Yigit Boyar2bbad0c2014-09-16 18:28:03 -0700319 tabContainer.layout(l, containerHeight - tabHeight - lp.bottomMargin, r,
320 containerHeight - lp.bottomMargin);
Adam Powelldae78242011-04-25 15:23:41 -0700321 }
Adam Powella72ef622011-07-06 22:53:11 -0700322
323 boolean needsInvalidate = false;
324 if (mIsSplit) {
325 if (mSplitBackground != null) {
326 mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
327 needsInvalidate = true;
328 }
329 } else {
330 if (mBackground != null) {
Chet Haaseccd3da22014-09-12 18:03:55 -0700331 if (mActionBarView.getVisibility() == View.VISIBLE) {
332 mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
333 mActionBarView.getRight(), mActionBarView.getBottom());
334 } else if (mActionContextView != null &&
335 mActionContextView.getVisibility() == View.VISIBLE) {
336 mBackground.setBounds(mActionContextView.getLeft(), mActionContextView.getTop(),
337 mActionContextView.getRight(), mActionContextView.getBottom());
338 } else {
339 mBackground.setBounds(0, 0, 0, 0);
340 }
Adam Powella72ef622011-07-06 22:53:11 -0700341 needsInvalidate = true;
342 }
Alan Viverette7f610fe2014-02-19 14:40:12 -0800343 mIsStacked = hasTabs;
344 if (hasTabs && mStackedBackground != null) {
345 mStackedBackground.setBounds(tabContainer.getLeft(), tabContainer.getTop(),
346 tabContainer.getRight(), tabContainer.getBottom());
Adam Powella72ef622011-07-06 22:53:11 -0700347 needsInvalidate = true;
348 }
349 }
350
351 if (needsInvalidate) {
352 invalidate();
353 }
Adam Powelldae78242011-04-25 15:23:41 -0700354 }
Alan Viverette7f610fe2014-02-19 14:40:12 -0800355
356 /**
357 * Dummy drawable so that we don't break background display lists and
358 * projection surfaces.
359 */
360 private class ActionBarBackgroundDrawable extends Drawable {
Chris Craik1e610d42014-08-13 10:37:18 -0700361 @Override
362 public void draw(Canvas canvas) {
Alan Viverette7f610fe2014-02-19 14:40:12 -0800363 if (mIsSplit) {
Chris Craik77b5cad2014-07-30 18:23:07 -0700364 if (mSplitBackground != null) {
Chris Craik1e610d42014-08-13 10:37:18 -0700365 mSplitBackground.draw(canvas);
Chris Craik77b5cad2014-07-30 18:23:07 -0700366 }
Alan Viverette7f610fe2014-02-19 14:40:12 -0800367 } else {
368 if (mBackground != null) {
Chris Craik1e610d42014-08-13 10:37:18 -0700369 mBackground.draw(canvas);
Alan Viverette7f610fe2014-02-19 14:40:12 -0800370 }
371 if (mStackedBackground != null && mIsStacked) {
Chris Craik1e610d42014-08-13 10:37:18 -0700372 mStackedBackground.draw(canvas);
Alan Viverette7f610fe2014-02-19 14:40:12 -0800373 }
374 }
Chris Craik77b5cad2014-07-30 18:23:07 -0700375 }
376
377 @Override
378 public void getOutline(@NonNull Outline outline) {
Chris Craik1e610d42014-08-13 10:37:18 -0700379 if (mIsSplit) {
380 if (mSplitBackground != null) {
381 mSplitBackground.getOutline(outline);
382 }
383 } else {
384 // ignore the stacked background for shadow casting
385 if (mBackground != null) {
386 mBackground.getOutline(outline);
387 }
Chris Craik77b5cad2014-07-30 18:23:07 -0700388 }
Alan Viverette7f610fe2014-02-19 14:40:12 -0800389 }
390
391 @Override
392 public void setAlpha(int alpha) {
393 }
394
395 @Override
Chris Craikbd3bfc52015-03-02 10:43:29 -0800396 public void setColorFilter(ColorFilter colorFilter) {
Alan Viverette7f610fe2014-02-19 14:40:12 -0800397 }
398
399 @Override
400 public int getOpacity() {
Adam Powellf849a5e2014-09-11 15:09:36 -0700401 if (mIsSplit) {
402 if (mSplitBackground != null
403 && mSplitBackground.getOpacity() == PixelFormat.OPAQUE) {
404 return PixelFormat.OPAQUE;
405 }
406 } else {
407 if (mIsStacked && (mStackedBackground == null
408 || mStackedBackground.getOpacity() != PixelFormat.OPAQUE)) {
409 return PixelFormat.UNKNOWN;
410 }
411 if (!isCollapsed(mActionBarView) && mBackground != null
412 && mBackground.getOpacity() == PixelFormat.OPAQUE) {
413 return PixelFormat.OPAQUE;
414 }
415 }
416
417 return PixelFormat.UNKNOWN;
Alan Viverette7f610fe2014-02-19 14:40:12 -0800418 }
419 }
Adam Powell45f1e082010-12-10 14:20:13 -0800420}