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             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             mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
    300         }
    301 
    302         boolean needsInvalidate = false;
    303         if (mIsSplit) {
    304             if (mSplitBackground != null) {
    305                 mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
    306                 needsInvalidate = true;
    307             }
    308         } else {
    309             if (mBackground != null) {
    310                 mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
    311                         mActionBarView.getRight(), mActionBarView.getBottom());
    312                 needsInvalidate = true;
    313             }
    314             if ((mIsStacked = hasTabs && mStackedBackground != null)) {
    315                 mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(),
    316                         mTabContainer.getRight(), mTabContainer.getBottom());
    317                 needsInvalidate = true;
    318             }
    319         }
    320 
    321         if (needsInvalidate) {
    322             invalidate();
    323         }
    324     }
    325 }
    326