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