ActionBarContainer.java revision 4457e85a7090ad51726d50a4daf981d917cceedd
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.app.ActionBar;
20import android.content.Context;
21import android.content.res.TypedArray;
22import android.graphics.Canvas;
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
47    public ActionBarContainer(Context context) {
48        this(context, null);
49    }
50
51    public ActionBarContainer(Context context, AttributeSet attrs) {
52        super(context, attrs);
53
54        setBackgroundDrawable(null);
55
56        TypedArray a = context.obtainStyledAttributes(attrs,
57                com.android.internal.R.styleable.ActionBar);
58        mBackground = a.getDrawable(com.android.internal.R.styleable.ActionBar_background);
59        mStackedBackground = a.getDrawable(
60                com.android.internal.R.styleable.ActionBar_backgroundStacked);
61
62        if (getId() == com.android.internal.R.id.split_action_bar) {
63            mIsSplit = true;
64            mSplitBackground = a.getDrawable(
65                    com.android.internal.R.styleable.ActionBar_backgroundSplit);
66        }
67        a.recycle();
68
69        setWillNotDraw(mIsSplit ? mSplitBackground == null :
70                mBackground == null && mStackedBackground == null);
71    }
72
73    @Override
74    public void onFinishInflate() {
75        super.onFinishInflate();
76        mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
77    }
78
79    public void setPrimaryBackground(Drawable bg) {
80        if (mBackground != null) {
81            mBackground.setCallback(null);
82            unscheduleDrawable(mBackground);
83        }
84        mBackground = bg;
85        if (bg != null) {
86            bg.setCallback(this);
87        }
88        setWillNotDraw(mIsSplit ? mSplitBackground == null :
89                mBackground == null && mStackedBackground == null);
90        invalidate();
91    }
92
93    public void setStackedBackground(Drawable bg) {
94        if (mStackedBackground != null) {
95            mStackedBackground.setCallback(null);
96            unscheduleDrawable(mStackedBackground);
97        }
98        mStackedBackground = bg;
99        if (bg != null) {
100            bg.setCallback(this);
101        }
102        setWillNotDraw(mIsSplit ? mSplitBackground == null :
103                mBackground == null && mStackedBackground == null);
104        invalidate();
105    }
106
107    public void setSplitBackground(Drawable bg) {
108        if (mSplitBackground != null) {
109            mSplitBackground.setCallback(null);
110            unscheduleDrawable(mSplitBackground);
111        }
112        mSplitBackground = bg;
113        if (bg != null) {
114            bg.setCallback(this);
115        }
116        setWillNotDraw(mIsSplit ? mSplitBackground == null :
117                mBackground == null && mStackedBackground == null);
118        invalidate();
119    }
120
121    @Override
122    public void setVisibility(int visibility) {
123        super.setVisibility(visibility);
124        final boolean isVisible = visibility == VISIBLE;
125        if (mBackground != null) mBackground.setVisible(isVisible, false);
126        if (mStackedBackground != null) mStackedBackground.setVisible(isVisible, false);
127        if (mSplitBackground != null) mSplitBackground.setVisible(isVisible, false);
128    }
129
130    @Override
131    protected boolean verifyDrawable(Drawable who) {
132        return (who == mBackground && !mIsSplit) || (who == mStackedBackground && mIsStacked) ||
133                (who == mSplitBackground && mIsSplit) || super.verifyDrawable(who);
134    }
135
136    @Override
137    protected void drawableStateChanged() {
138        super.drawableStateChanged();
139        if (mBackground != null && mBackground.isStateful()) {
140            mBackground.setState(getDrawableState());
141        }
142        if (mStackedBackground != null && mStackedBackground.isStateful()) {
143            mStackedBackground.setState(getDrawableState());
144        }
145        if (mSplitBackground != null && mSplitBackground.isStateful()) {
146            mSplitBackground.setState(getDrawableState());
147        }
148    }
149
150    @Override
151    public void jumpDrawablesToCurrentState() {
152        super.jumpDrawablesToCurrentState();
153        if (mBackground != null) {
154            mBackground.jumpToCurrentState();
155        }
156        if (mStackedBackground != null) {
157            mStackedBackground.jumpToCurrentState();
158        }
159        if (mSplitBackground != null) {
160            mSplitBackground.jumpToCurrentState();
161        }
162    }
163
164    /**
165     * @hide
166     */
167    @Override
168    public void onResolveDrawables(int layoutDirection) {
169        super.onResolveDrawables(layoutDirection);
170        if (mBackground != null) {
171            mBackground.setLayoutDirection(layoutDirection);
172        }
173        if (mStackedBackground != null) {
174            mStackedBackground.setLayoutDirection(layoutDirection);
175        }
176        if (mSplitBackground != null) {
177            mSplitBackground.setLayoutDirection(layoutDirection);
178        }
179    }
180
181    /**
182     * Set the action bar into a "transitioning" state. While transitioning
183     * the bar will block focus and touch from all of its descendants. This
184     * prevents the user from interacting with the bar while it is animating
185     * in or out.
186     *
187     * @param isTransitioning true if the bar is currently transitioning, false otherwise.
188     */
189    public void setTransitioning(boolean isTransitioning) {
190        mIsTransitioning = isTransitioning;
191        setDescendantFocusability(isTransitioning ? FOCUS_BLOCK_DESCENDANTS
192                : FOCUS_AFTER_DESCENDANTS);
193    }
194
195    @Override
196    public boolean onInterceptTouchEvent(MotionEvent ev) {
197        return mIsTransitioning || super.onInterceptTouchEvent(ev);
198    }
199
200    @Override
201    public boolean onTouchEvent(MotionEvent ev) {
202        super.onTouchEvent(ev);
203
204        // An action bar always eats touch events.
205        return true;
206    }
207
208    @Override
209    public boolean onHoverEvent(MotionEvent ev) {
210        super.onHoverEvent(ev);
211
212        // An action bar always eats hover events.
213        return true;
214    }
215
216    public void setTabContainer(ScrollingTabContainerView tabView) {
217        if (mTabContainer != null) {
218            removeView(mTabContainer);
219        }
220        mTabContainer = tabView;
221        if (tabView != null) {
222            addView(tabView);
223            final ViewGroup.LayoutParams lp = tabView.getLayoutParams();
224            lp.width = LayoutParams.MATCH_PARENT;
225            lp.height = LayoutParams.WRAP_CONTENT;
226            tabView.setAllowCollapse(false);
227        }
228    }
229
230    public View getTabContainer() {
231        return mTabContainer;
232    }
233
234    @Override
235    public void onDraw(Canvas canvas) {
236        if (getWidth() == 0 || getHeight() == 0) {
237            return;
238        }
239
240        if (mIsSplit) {
241            if (mSplitBackground != null) mSplitBackground.draw(canvas);
242        } else {
243            if (mBackground != null) {
244                mBackground.draw(canvas);
245            }
246            if (mStackedBackground != null && mIsStacked) {
247                mStackedBackground.draw(canvas);
248            }
249        }
250    }
251
252    @Override
253    public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
254        // No starting an action mode for an action bar child! (Where would it go?)
255        return null;
256    }
257
258    @Override
259    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
260        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
261
262        if (mActionBarView == null) return;
263
264        final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
265        final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
266                mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
267
268        if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
269            final int mode = MeasureSpec.getMode(heightMeasureSpec);
270            if (mode == MeasureSpec.AT_MOST) {
271                final int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
272                setMeasuredDimension(getMeasuredWidth(),
273                        Math.min(actionBarViewHeight + mTabContainer.getMeasuredHeight(),
274                                maxHeight));
275            }
276        }
277    }
278
279    @Override
280    public void onLayout(boolean changed, int l, int t, int r, int b) {
281        super.onLayout(changed, l, t, r, b);
282
283        final boolean hasTabs = mTabContainer != null && mTabContainer.getVisibility() != GONE;
284
285        if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
286            final int containerHeight = getMeasuredHeight();
287            final int tabHeight = mTabContainer.getMeasuredHeight();
288
289            if ((mActionBarView.getDisplayOptions() & ActionBar.DISPLAY_SHOW_HOME) == 0) {
290                // Not showing home, put tabs on top.
291                final int count = getChildCount();
292                for (int i = 0; i < count; i++) {
293                    final View child = getChildAt(i);
294
295                    if (child == mTabContainer) continue;
296
297                    if (!mActionBarView.isCollapsed()) {
298                        child.offsetTopAndBottom(tabHeight);
299                    }
300                }
301                mTabContainer.layout(l, 0, r, tabHeight);
302            } else {
303                mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
304            }
305        }
306
307        boolean needsInvalidate = false;
308        if (mIsSplit) {
309            if (mSplitBackground != null) {
310                mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
311                needsInvalidate = true;
312            }
313        } else {
314            if (mBackground != null) {
315                mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
316                        mActionBarView.getRight(), mActionBarView.getBottom());
317                needsInvalidate = true;
318            }
319            if ((mIsStacked = hasTabs && mStackedBackground != null)) {
320                mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(),
321                        mTabContainer.getRight(), mTabContainer.getBottom());
322                needsInvalidate = true;
323            }
324        }
325
326        if (needsInvalidate) {
327            invalidate();
328        }
329    }
330}
331