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         mBackground = bg;
     81         invalidate();
     82     }
     83 
     84     public void setStackedBackground(Drawable bg) {
     85         mStackedBackground = bg;
     86         invalidate();
     87     }
     88 
     89     public void setSplitBackground(Drawable bg) {
     90         mSplitBackground = bg;
     91         invalidate();
     92     }
     93 
     94     /**
     95      * Set the action bar into a "transitioning" state. While transitioning
     96      * the bar will block focus and touch from all of its descendants. This
     97      * prevents the user from interacting with the bar while it is animating
     98      * in or out.
     99      *
    100      * @param isTransitioning true if the bar is currently transitioning, false otherwise.
    101      */
    102     public void setTransitioning(boolean isTransitioning) {
    103         mIsTransitioning = isTransitioning;
    104         setDescendantFocusability(isTransitioning ? FOCUS_BLOCK_DESCENDANTS
    105                 : FOCUS_AFTER_DESCENDANTS);
    106     }
    107 
    108     @Override
    109     public boolean onInterceptTouchEvent(MotionEvent ev) {
    110         return mIsTransitioning || super.onInterceptTouchEvent(ev);
    111     }
    112 
    113     @Override
    114     public boolean onTouchEvent(MotionEvent ev) {
    115         super.onTouchEvent(ev);
    116 
    117         // An action bar always eats touch events.
    118         return true;
    119     }
    120 
    121     @Override
    122     public boolean onHoverEvent(MotionEvent ev) {
    123         super.onHoverEvent(ev);
    124 
    125         // An action bar always eats hover events.
    126         return true;
    127     }
    128 
    129     public void setTabContainer(ScrollingTabContainerView tabView) {
    130         if (mTabContainer != null) {
    131             removeView(mTabContainer);
    132         }
    133         mTabContainer = tabView;
    134         if (tabView != null) {
    135             addView(tabView);
    136             final ViewGroup.LayoutParams lp = tabView.getLayoutParams();
    137             lp.width = LayoutParams.MATCH_PARENT;
    138             lp.height = LayoutParams.WRAP_CONTENT;
    139             tabView.setAllowCollapse(false);
    140         }
    141     }
    142 
    143     public View getTabContainer() {
    144         return mTabContainer;
    145     }
    146 
    147     @Override
    148     public void onDraw(Canvas canvas) {
    149         if (getWidth() == 0 || getHeight() == 0) {
    150             return;
    151         }
    152 
    153         if (mIsSplit) {
    154             if (mSplitBackground != null) mSplitBackground.draw(canvas);
    155         } else {
    156             if (mBackground != null) {
    157                 mBackground.draw(canvas);
    158             }
    159             if (mStackedBackground != null && mIsStacked) {
    160                 mStackedBackground.draw(canvas);
    161             }
    162         }
    163     }
    164 
    165     @Override
    166     public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
    167         // No starting an action mode for an action bar child! (Where would it go?)
    168         return null;
    169     }
    170 
    171     @Override
    172     public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    173         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    174 
    175         if (mActionBarView == null) return;
    176 
    177         final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
    178         final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
    179                 mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
    180 
    181         if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
    182             final int mode = MeasureSpec.getMode(heightMeasureSpec);
    183             if (mode == MeasureSpec.AT_MOST) {
    184                 final int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
    185                 setMeasuredDimension(getMeasuredWidth(),
    186                         Math.min(actionBarViewHeight + mTabContainer.getMeasuredHeight(),
    187                                 maxHeight));
    188             }
    189         }
    190     }
    191 
    192     @Override
    193     public void onLayout(boolean changed, int l, int t, int r, int b) {
    194         super.onLayout(changed, l, t, r, b);
    195 
    196         final boolean hasTabs = mTabContainer != null && mTabContainer.getVisibility() != GONE;
    197 
    198         if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
    199             final int containerHeight = getMeasuredHeight();
    200             final int tabHeight = mTabContainer.getMeasuredHeight();
    201 
    202             if ((mActionBarView.getDisplayOptions() & ActionBar.DISPLAY_SHOW_HOME) == 0) {
    203                 // Not showing home, put tabs on top.
    204                 final int count = getChildCount();
    205                 for (int i = 0; i < count; i++) {
    206                     final View child = getChildAt(i);
    207 
    208                     if (child == mTabContainer) continue;
    209 
    210                     if (!mActionBarView.isCollapsed()) {
    211                         child.offsetTopAndBottom(tabHeight);
    212                     }
    213                 }
    214                 mTabContainer.layout(l, 0, r, tabHeight);
    215             } else {
    216                 mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
    217             }
    218         }
    219 
    220         boolean needsInvalidate = false;
    221         if (mIsSplit) {
    222             if (mSplitBackground != null) {
    223                 mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
    224                 needsInvalidate = true;
    225             }
    226         } else {
    227             if (mBackground != null) {
    228                 mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
    229                         mActionBarView.getRight(), mActionBarView.getBottom());
    230                 needsInvalidate = true;
    231             }
    232             if ((mIsStacked = hasTabs && mStackedBackground != null)) {
    233                 mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(),
    234                         mTabContainer.getRight(), mTabContainer.getBottom());
    235                 needsInvalidate = true;
    236             }
    237         }
    238 
    239         if (needsInvalidate) {
    240             invalidate();
    241         }
    242     }
    243 }
    244