ActionBarContainer.java revision e43340c80dc66c45edc793ecd0343774aa34d108
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 ActionBarView 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 = (ActionBarView) 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    @Override
255    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
256        if (mActionBarView == null &&
257                MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST && mHeight >= 0) {
258            heightMeasureSpec = MeasureSpec.makeMeasureSpec(
259                    Math.min(mHeight, MeasureSpec.getSize(heightMeasureSpec)), MeasureSpec.AT_MOST);
260        }
261        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
262
263        if (mActionBarView == null) return;
264
265        final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
266        final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
267                mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
268
269        if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
270            final int mode = MeasureSpec.getMode(heightMeasureSpec);
271            if (mode == MeasureSpec.AT_MOST) {
272                final int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
273                setMeasuredDimension(getMeasuredWidth(),
274                        Math.min(actionBarViewHeight + mTabContainer.getMeasuredHeight(),
275                                maxHeight));
276            }
277        }
278    }
279
280    @Override
281    public void onLayout(boolean changed, int l, int t, int r, int b) {
282        super.onLayout(changed, l, t, r, b);
283
284        final View tabContainer = mTabContainer;
285        final boolean hasTabs = tabContainer != null && tabContainer.getVisibility() != GONE;
286
287        if (tabContainer != null && tabContainer.getVisibility() != GONE) {
288            final int containerHeight = getMeasuredHeight();
289            final int tabHeight = tabContainer.getMeasuredHeight();
290            tabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
291        }
292
293        boolean needsInvalidate = false;
294        if (mIsSplit) {
295            if (mSplitBackground != null) {
296                mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
297                needsInvalidate = true;
298            }
299        } else {
300            if (mBackground != null) {
301                final ActionBarView actionBarView = mActionBarView;
302                mBackground.setBounds(actionBarView.getLeft(), actionBarView.getTop(),
303                        actionBarView.getRight(), actionBarView.getBottom());
304                needsInvalidate = true;
305            }
306            mIsStacked = hasTabs;
307            if (hasTabs && mStackedBackground != null) {
308                mStackedBackground.setBounds(tabContainer.getLeft(), tabContainer.getTop(),
309                        tabContainer.getRight(), tabContainer.getBottom());
310                needsInvalidate = true;
311            }
312        }
313
314        if (needsInvalidate) {
315            invalidate();
316        }
317    }
318
319    /**
320     * Dummy drawable so that we don't break background display lists and
321     * projection surfaces.
322     */
323    private class ActionBarBackgroundDrawable extends Drawable {
324        @Override
325        public void draw(Canvas canvas) {
326            if (mIsSplit) {
327                if (mSplitBackground != null) mSplitBackground.draw(canvas);
328            } else {
329                if (mBackground != null) {
330                    mBackground.draw(canvas);
331                }
332                if (mStackedBackground != null && mIsStacked) {
333                    mStackedBackground.draw(canvas);
334                }
335            }
336        }
337
338        @Override
339        public void setAlpha(int alpha) {
340        }
341
342        @Override
343        public void setColorFilter(ColorFilter cf) {
344        }
345
346        @Override
347        public int getOpacity() {
348            return 0;
349        }
350    }
351}
352