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