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