Home | History | Annotate | Download | only in widget
      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 
     17 package com.android.internal.widget;
     18 
     19 import android.app.ActionBar;
     20 import android.content.Context;
     21 import android.content.res.TypedArray;
     22 import android.graphics.Canvas;
     23 import android.graphics.drawable.Drawable;
     24 import android.util.AttributeSet;
     25 import android.view.ActionMode;
     26 import android.view.MotionEvent;
     27 import android.view.View;
     28 import android.view.ViewGroup;
     29 import 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  */
     36 public 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