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 package com.android.internal.widget;
     17 
     18 import com.android.internal.R;
     19 
     20 import android.widget.ActionMenuPresenter;
     21 import android.widget.ActionMenuView;
     22 import com.android.internal.view.menu.MenuBuilder;
     23 
     24 import android.content.Context;
     25 import android.content.res.TypedArray;
     26 import android.graphics.drawable.Drawable;
     27 import android.text.TextUtils;
     28 import android.util.AttributeSet;
     29 import android.view.ActionMode;
     30 import android.view.LayoutInflater;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.view.accessibility.AccessibilityEvent;
     34 import android.widget.LinearLayout;
     35 import android.widget.TextView;
     36 
     37 /**
     38  * @hide
     39  */
     40 public class ActionBarContextView extends AbsActionBarView {
     41     private static final String TAG = "ActionBarContextView";
     42 
     43     private CharSequence mTitle;
     44     private CharSequence mSubtitle;
     45 
     46     private View mClose;
     47     private View mCustomView;
     48     private LinearLayout mTitleLayout;
     49     private TextView mTitleView;
     50     private TextView mSubtitleView;
     51     private int mTitleStyleRes;
     52     private int mSubtitleStyleRes;
     53     private Drawable mSplitBackground;
     54     private boolean mTitleOptional;
     55     private int mCloseItemLayout;
     56 
     57     public ActionBarContextView(Context context) {
     58         this(context, null);
     59     }
     60 
     61     public ActionBarContextView(Context context, AttributeSet attrs) {
     62         this(context, attrs, com.android.internal.R.attr.actionModeStyle);
     63     }
     64 
     65     public ActionBarContextView(Context context, AttributeSet attrs, int defStyleAttr) {
     66         this(context, attrs, defStyleAttr, 0);
     67     }
     68 
     69     public ActionBarContextView(
     70             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
     71         super(context, attrs, defStyleAttr, defStyleRes);
     72 
     73         final TypedArray a = context.obtainStyledAttributes(
     74                 attrs, R.styleable.ActionMode, defStyleAttr, defStyleRes);
     75         setBackground(a.getDrawable(
     76                 com.android.internal.R.styleable.ActionMode_background));
     77         mTitleStyleRes = a.getResourceId(
     78                 com.android.internal.R.styleable.ActionMode_titleTextStyle, 0);
     79         mSubtitleStyleRes = a.getResourceId(
     80                 com.android.internal.R.styleable.ActionMode_subtitleTextStyle, 0);
     81 
     82         mContentHeight = a.getLayoutDimension(
     83                 com.android.internal.R.styleable.ActionMode_height, 0);
     84 
     85         mSplitBackground = a.getDrawable(
     86                 com.android.internal.R.styleable.ActionMode_backgroundSplit);
     87 
     88         mCloseItemLayout = a.getResourceId(
     89                 com.android.internal.R.styleable.ActionMode_closeItemLayout,
     90                 R.layout.action_mode_close_item);
     91 
     92         a.recycle();
     93     }
     94 
     95     @Override
     96     public void onDetachedFromWindow() {
     97         super.onDetachedFromWindow();
     98         if (mActionMenuPresenter != null) {
     99             mActionMenuPresenter.hideOverflowMenu();
    100             mActionMenuPresenter.hideSubMenus();
    101         }
    102     }
    103 
    104     @Override
    105     public void setSplitToolbar(boolean split) {
    106         if (mSplitActionBar != split) {
    107             if (mActionMenuPresenter != null) {
    108                 // Mode is already active; move everything over and adjust the menu itself.
    109                 final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
    110                         LayoutParams.MATCH_PARENT);
    111                 if (!split) {
    112                     mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
    113                     mMenuView.setBackground(null);
    114                     final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
    115                     if (oldParent != null) oldParent.removeView(mMenuView);
    116                     addView(mMenuView, layoutParams);
    117                 } else {
    118                     // Allow full screen width in split mode.
    119                     mActionMenuPresenter.setWidthLimit(
    120                             getContext().getResources().getDisplayMetrics().widthPixels, true);
    121                     // No limit to the item count; use whatever will fit.
    122                     mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
    123                     // Span the whole width
    124                     layoutParams.width = LayoutParams.MATCH_PARENT;
    125                     layoutParams.height = mContentHeight;
    126                     mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
    127                     mMenuView.setBackground(mSplitBackground);
    128                     final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
    129                     if (oldParent != null) oldParent.removeView(mMenuView);
    130                     mSplitView.addView(mMenuView, layoutParams);
    131                 }
    132             }
    133             super.setSplitToolbar(split);
    134         }
    135     }
    136 
    137     public void setContentHeight(int height) {
    138         mContentHeight = height;
    139     }
    140 
    141     public void setCustomView(View view) {
    142         if (mCustomView != null) {
    143             removeView(mCustomView);
    144         }
    145         mCustomView = view;
    146         if (view != null && mTitleLayout != null) {
    147             removeView(mTitleLayout);
    148             mTitleLayout = null;
    149         }
    150         if (view != null) {
    151             addView(view);
    152         }
    153         requestLayout();
    154     }
    155 
    156     public void setTitle(CharSequence title) {
    157         mTitle = title;
    158         initTitle();
    159     }
    160 
    161     public void setSubtitle(CharSequence subtitle) {
    162         mSubtitle = subtitle;
    163         initTitle();
    164     }
    165 
    166     public CharSequence getTitle() {
    167         return mTitle;
    168     }
    169 
    170     public CharSequence getSubtitle() {
    171         return mSubtitle;
    172     }
    173 
    174     private void initTitle() {
    175         if (mTitleLayout == null) {
    176             LayoutInflater inflater = LayoutInflater.from(getContext());
    177             inflater.inflate(R.layout.action_bar_title_item, this);
    178             mTitleLayout = (LinearLayout) getChildAt(getChildCount() - 1);
    179             mTitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_title);
    180             mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.action_bar_subtitle);
    181             if (mTitleStyleRes != 0) {
    182                 mTitleView.setTextAppearance(mTitleStyleRes);
    183             }
    184             if (mSubtitleStyleRes != 0) {
    185                 mSubtitleView.setTextAppearance(mSubtitleStyleRes);
    186             }
    187         }
    188 
    189         mTitleView.setText(mTitle);
    190         mSubtitleView.setText(mSubtitle);
    191 
    192         final boolean hasTitle = !TextUtils.isEmpty(mTitle);
    193         final boolean hasSubtitle = !TextUtils.isEmpty(mSubtitle);
    194         mSubtitleView.setVisibility(hasSubtitle ? VISIBLE : GONE);
    195         mTitleLayout.setVisibility(hasTitle || hasSubtitle ? VISIBLE : GONE);
    196         if (mTitleLayout.getParent() == null) {
    197             addView(mTitleLayout);
    198         }
    199     }
    200 
    201     public void initForMode(final ActionMode mode) {
    202         if (mClose == null) {
    203             LayoutInflater inflater = LayoutInflater.from(mContext);
    204             mClose = inflater.inflate(mCloseItemLayout, this, false);
    205             addView(mClose);
    206         } else if (mClose.getParent() == null) {
    207             addView(mClose);
    208         }
    209 
    210         View closeButton = mClose.findViewById(R.id.action_mode_close_button);
    211         closeButton.setOnClickListener(new OnClickListener() {
    212             public void onClick(View v) {
    213                 mode.finish();
    214             }
    215         });
    216 
    217         final MenuBuilder menu = (MenuBuilder) mode.getMenu();
    218         if (mActionMenuPresenter != null) {
    219             mActionMenuPresenter.dismissPopupMenus();
    220         }
    221         mActionMenuPresenter = new ActionMenuPresenter(mContext);
    222         mActionMenuPresenter.setReserveOverflow(true);
    223 
    224         final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
    225                 LayoutParams.MATCH_PARENT);
    226         if (!mSplitActionBar) {
    227             menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
    228             mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
    229             mMenuView.setBackground(null);
    230             addView(mMenuView, layoutParams);
    231         } else {
    232             // Allow full screen width in split mode.
    233             mActionMenuPresenter.setWidthLimit(
    234                     getContext().getResources().getDisplayMetrics().widthPixels, true);
    235             // No limit to the item count; use whatever will fit.
    236             mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
    237             // Span the whole width
    238             layoutParams.width = LayoutParams.MATCH_PARENT;
    239             layoutParams.height = mContentHeight;
    240             menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
    241             mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
    242             mMenuView.setBackgroundDrawable(mSplitBackground);
    243             mSplitView.addView(mMenuView, layoutParams);
    244         }
    245     }
    246 
    247     public void closeMode() {
    248         if (mClose == null) {
    249             killMode();
    250             return;
    251         }
    252 
    253     }
    254 
    255     public void killMode() {
    256         removeAllViews();
    257         if (mSplitView != null) {
    258             mSplitView.removeView(mMenuView);
    259         }
    260         mCustomView = null;
    261         mMenuView = null;
    262     }
    263 
    264     @Override
    265     public boolean showOverflowMenu() {
    266         if (mActionMenuPresenter != null) {
    267             return mActionMenuPresenter.showOverflowMenu();
    268         }
    269         return false;
    270     }
    271 
    272     @Override
    273     public boolean hideOverflowMenu() {
    274         if (mActionMenuPresenter != null) {
    275             return mActionMenuPresenter.hideOverflowMenu();
    276         }
    277         return false;
    278     }
    279 
    280     @Override
    281     public boolean isOverflowMenuShowing() {
    282         if (mActionMenuPresenter != null) {
    283             return mActionMenuPresenter.isOverflowMenuShowing();
    284         }
    285         return false;
    286     }
    287 
    288     @Override
    289     protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
    290         // Used by custom views if they don't supply layout params. Everything else
    291         // added to an ActionBarContextView should have them already.
    292         return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    293     }
    294 
    295     @Override
    296     public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
    297         return new MarginLayoutParams(getContext(), attrs);
    298     }
    299 
    300     @Override
    301     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    302         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    303         if (widthMode != MeasureSpec.EXACTLY) {
    304             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
    305                     "with android:layout_width=\"match_parent\" (or fill_parent)");
    306         }
    307 
    308         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    309         if (heightMode == MeasureSpec.UNSPECIFIED) {
    310             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
    311                     "with android:layout_height=\"wrap_content\"");
    312         }
    313 
    314         final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
    315 
    316         int maxHeight = mContentHeight > 0 ?
    317                 mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
    318 
    319         final int verticalPadding = getPaddingTop() + getPaddingBottom();
    320         int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
    321         final int height = maxHeight - verticalPadding;
    322         final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
    323 
    324         if (mClose != null) {
    325             availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
    326             MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
    327             availableWidth -= lp.leftMargin + lp.rightMargin;
    328         }
    329 
    330         if (mMenuView != null && mMenuView.getParent() == this) {
    331             availableWidth = measureChildView(mMenuView, availableWidth,
    332                     childSpecHeight, 0);
    333         }
    334 
    335         if (mTitleLayout != null && mCustomView == null) {
    336             if (mTitleOptional) {
    337                 final int titleWidthSpec = MeasureSpec.makeSafeMeasureSpec(contentWidth,
    338                         MeasureSpec.UNSPECIFIED);
    339                 mTitleLayout.measure(titleWidthSpec, childSpecHeight);
    340                 final int titleWidth = mTitleLayout.getMeasuredWidth();
    341                 final boolean titleFits = titleWidth <= availableWidth;
    342                 if (titleFits) {
    343                     availableWidth -= titleWidth;
    344                 }
    345                 mTitleLayout.setVisibility(titleFits ? VISIBLE : GONE);
    346             } else {
    347                 availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
    348             }
    349         }
    350 
    351         if (mCustomView != null) {
    352             ViewGroup.LayoutParams lp = mCustomView.getLayoutParams();
    353             final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
    354                     MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
    355             final int customWidth = lp.width >= 0 ?
    356                     Math.min(lp.width, availableWidth) : availableWidth;
    357             final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
    358                     MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
    359             final int customHeight = lp.height >= 0 ?
    360                     Math.min(lp.height, height) : height;
    361             mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
    362                     MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
    363         }
    364 
    365         if (mContentHeight <= 0) {
    366             int measuredHeight = 0;
    367             final int count = getChildCount();
    368             for (int i = 0; i < count; i++) {
    369                 View v = getChildAt(i);
    370                 int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
    371                 if (paddedViewHeight > measuredHeight) {
    372                     measuredHeight = paddedViewHeight;
    373                 }
    374             }
    375             setMeasuredDimension(contentWidth, measuredHeight);
    376         } else {
    377             setMeasuredDimension(contentWidth, maxHeight);
    378         }
    379     }
    380 
    381     @Override
    382     protected void onLayout(boolean changed, int l, int t, int r, int b) {
    383         final boolean isLayoutRtl = isLayoutRtl();
    384         int x = isLayoutRtl ? r - l - getPaddingRight() : getPaddingLeft();
    385         final int y = getPaddingTop();
    386         final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
    387 
    388         if (mClose != null && mClose.getVisibility() != GONE) {
    389             MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
    390             final int startMargin = (isLayoutRtl ? lp.rightMargin : lp.leftMargin);
    391             final int endMargin = (isLayoutRtl ? lp.leftMargin : lp.rightMargin);
    392             x = next(x, startMargin, isLayoutRtl);
    393             x += positionChild(mClose, x, y, contentHeight, isLayoutRtl);
    394             x = next(x, endMargin, isLayoutRtl);
    395 
    396         }
    397 
    398         if (mTitleLayout != null && mCustomView == null && mTitleLayout.getVisibility() != GONE) {
    399             x += positionChild(mTitleLayout, x, y, contentHeight, isLayoutRtl);
    400         }
    401 
    402         if (mCustomView != null) {
    403             x += positionChild(mCustomView, x, y, contentHeight, isLayoutRtl);
    404         }
    405 
    406         x = isLayoutRtl ? getPaddingLeft() : r - l - getPaddingRight();
    407 
    408         if (mMenuView != null) {
    409             x += positionChild(mMenuView, x, y, contentHeight, !isLayoutRtl);
    410         }
    411     }
    412 
    413     @Override
    414     public boolean shouldDelayChildPressedState() {
    415         return false;
    416     }
    417 
    418     @Override
    419     public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
    420         if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
    421             // Action mode started
    422             event.setSource(this);
    423             event.setClassName(getClass().getName());
    424             event.setPackageName(getContext().getPackageName());
    425             event.setContentDescription(mTitle);
    426         } else {
    427             super.onInitializeAccessibilityEventInternal(event);
    428         }
    429     }
    430 
    431     public void setTitleOptional(boolean titleOptional) {
    432         if (titleOptional != mTitleOptional) {
    433             requestLayout();
    434         }
    435         mTitleOptional = titleOptional;
    436     }
    437 
    438     public boolean isTitleOptional() {
    439         return mTitleOptional;
    440     }
    441 }
    442