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