2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com
.actionbarsherlock
.internal
.view
.menu
;
19 import java
.util
.HashSet
;
21 import android
.content
.Context
;
22 import android
.content
.res
.TypedArray
;
23 import android
.graphics
.Rect
;
24 import android
.graphics
.drawable
.Drawable
;
25 import android
.os
.Build
;
26 import android
.text
.TextUtils
;
27 import android
.util
.AttributeSet
;
28 import android
.view
.Gravity
;
29 import android
.view
.MotionEvent
;
30 import android
.view
.View
;
31 import android
.view
.accessibility
.AccessibilityEvent
;
32 import android
.widget
.ImageButton
;
33 import android
.widget
.LinearLayout
;
34 import android
.widget
.Toast
;
36 import com
.actionbarsherlock
.R
;
37 import com
.actionbarsherlock
.internal
.view
.View_HasStateListenerSupport
;
38 import com
.actionbarsherlock
.internal
.view
.View_OnAttachStateChangeListener
;
39 import com
.actionbarsherlock
.internal
.widget
.CapitalizingButton
;
41 import static com
.actionbarsherlock
.internal
.ResourcesCompat
.getResources_getBoolean
;
46 public class ActionMenuItemView
extends LinearLayout
47 implements MenuView
.ItemView
, View
.OnClickListener
, View
.OnLongClickListener
,
48 ActionMenuView
.ActionMenuChildView
, View_HasStateListenerSupport
{
49 //UNUSED private static final String TAG = "ActionMenuItemView";
51 private MenuItemImpl mItemData
;
52 private CharSequence mTitle
;
53 private MenuBuilder
.ItemInvoker mItemInvoker
;
55 private ImageButton mImageButton
;
56 private CapitalizingButton mTextButton
;
57 private boolean mAllowTextWithIcon
;
58 private boolean mExpandedFormat
;
59 private int mMinWidth
;
61 private final Set
<View_OnAttachStateChangeListener
> mListeners
= new HashSet
<View_OnAttachStateChangeListener
>();
63 public ActionMenuItemView(Context context
) {
67 public ActionMenuItemView(Context context
, AttributeSet attrs
) {
68 this(context
, attrs
, 0);
71 public ActionMenuItemView(Context context
, AttributeSet attrs
, int defStyle
) {
72 //TODO super(context, attrs, defStyle);
73 super(context
, attrs
);
74 mAllowTextWithIcon
= getResources_getBoolean(context
,
75 R
.bool
.abs__config_allowActionMenuItemTextWithIcon
);
76 TypedArray a
= context
.obtainStyledAttributes(attrs
,
77 R
.styleable
.SherlockActionMenuItemView
, 0, 0);
78 mMinWidth
= a
.getDimensionPixelSize(
79 R
.styleable
.SherlockActionMenuItemView_android_minWidth
, 0);
84 public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener
) {
85 mListeners
.add(listener
);
89 public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener
) {
90 mListeners
.remove(listener
);
94 protected void onAttachedToWindow() {
95 super.onAttachedToWindow();
96 for (View_OnAttachStateChangeListener listener
: mListeners
) {
97 listener
.onViewAttachedToWindow(this);
102 protected void onDetachedFromWindow() {
103 super.onDetachedFromWindow();
104 for (View_OnAttachStateChangeListener listener
: mListeners
) {
105 listener
.onViewDetachedFromWindow(this);
110 public void onFinishInflate() {
112 mImageButton
= (ImageButton
) findViewById(R
.id
.abs__imageButton
);
113 mTextButton
= (CapitalizingButton
) findViewById(R
.id
.abs__textButton
);
114 mImageButton
.setOnClickListener(this);
115 mTextButton
.setOnClickListener(this);
116 mImageButton
.setOnLongClickListener(this);
117 setOnClickListener(this);
118 setOnLongClickListener(this);
121 public MenuItemImpl
getItemData() {
125 public void initialize(MenuItemImpl itemData
, int menuType
) {
126 mItemData
= itemData
;
128 setIcon(itemData
.getIcon());
129 setTitle(itemData
.getTitleForItemView(this)); // Title only takes effect if there is no icon
130 setId(itemData
.getItemId());
132 setVisibility(itemData
.isVisible() ? View
.VISIBLE
: View
.GONE
);
133 setEnabled(itemData
.isEnabled());
137 public void setEnabled(boolean enabled
) {
138 super.setEnabled(enabled
);
139 mImageButton
.setEnabled(enabled
);
140 mTextButton
.setEnabled(enabled
);
143 public void onClick(View v
) {
144 if (mItemInvoker
!= null
) {
145 mItemInvoker
.invokeItem(mItemData
);
149 public void setItemInvoker(MenuBuilder
.ItemInvoker invoker
) {
150 mItemInvoker
= invoker
;
153 public boolean prefersCondensedTitle() {
157 public void setCheckable(boolean checkable
) {
158 // TODO Support checkable action items
161 public void setChecked(boolean checked
) {
162 // TODO Support checkable action items
165 public void setExpandedFormat(boolean expandedFormat
) {
166 if (mExpandedFormat
!= expandedFormat
) {
167 mExpandedFormat
= expandedFormat
;
168 if (mItemData
!= null
) {
169 mItemData
.actionFormatChanged();
174 private void updateTextButtonVisibility() {
175 boolean visible
= !TextUtils
.isEmpty(mTextButton
.getText());
176 visible
&= mImageButton
.getDrawable() == null
||
177 (mItemData
.showsTextAsAction() && (mAllowTextWithIcon
|| mExpandedFormat
));
179 mTextButton
.setVisibility(visible ? VISIBLE
: GONE
);
182 public void setIcon(Drawable icon
) {
183 mImageButton
.setImageDrawable(icon
);
185 mImageButton
.setVisibility(VISIBLE
);
187 mImageButton
.setVisibility(GONE
);
190 updateTextButtonVisibility();
193 public boolean hasText() {
194 return mTextButton
.getVisibility() != GONE
;
197 public void setShortcut(boolean showShortcut
, char shortcutKey
) {
198 // Action buttons don't show text for shortcut keys.
201 public void setTitle(CharSequence title
) {
204 mTextButton
.setTextCompat(mTitle
);
206 setContentDescription(mTitle
);
207 updateTextButtonVisibility();
211 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event
) {
212 onPopulateAccessibilityEvent(event
);
217 public void onPopulateAccessibilityEvent(AccessibilityEvent event
) {
218 if (Build
.VERSION
.SDK_INT
>= Build
.VERSION_CODES
.ICE_CREAM_SANDWICH
) {
219 super.onPopulateAccessibilityEvent(event
);
221 final CharSequence cdesc
= getContentDescription();
222 if (!TextUtils
.isEmpty(cdesc
)) {
223 event
.getText().add(cdesc
);
228 public boolean dispatchHoverEvent(MotionEvent event
) {
229 // Don't allow children to hover; we want this to be treated as a single component.
230 if (Build
.VERSION
.SDK_INT
>= Build
.VERSION_CODES
.ICE_CREAM_SANDWICH
) {
231 return onHoverEvent(event
);
236 public boolean showsIcon() {
240 public boolean needsDividerBefore() {
241 return hasText() && mItemData
.getIcon() == null
;
244 public boolean needsDividerAfter() {
249 public boolean onLongClick(View v
) {
251 // Don't show the cheat sheet for items that already show text.
255 final int[] screenPos
= new int[2];
256 final Rect displayFrame
= new Rect();
257 getLocationOnScreen(screenPos
);
258 getWindowVisibleDisplayFrame(displayFrame
);
260 final Context context
= getContext();
261 final int width
= getWidth();
262 final int height
= getHeight();
263 final int midy
= screenPos
[1] + height
/ 2;
264 final int screenWidth
= context
.getResources().getDisplayMetrics().widthPixels
;
266 Toast cheatSheet
= Toast
.makeText(context
, mItemData
.getTitle(), Toast
.LENGTH_SHORT
);
267 if (midy
< displayFrame
.height()) {
268 // Show along the top; follow action buttons
269 cheatSheet
.setGravity(Gravity
.TOP
| Gravity
.RIGHT
,
270 screenWidth
- screenPos
[0] - width
/ 2, height
);
272 // Show along the bottom center
273 cheatSheet
.setGravity(Gravity
.BOTTOM
| Gravity
.CENTER_HORIZONTAL
, 0, height
);
280 protected void onMeasure(int widthMeasureSpec
, int heightMeasureSpec
) {
281 super.onMeasure(widthMeasureSpec
, heightMeasureSpec
);
283 final int widthMode
= MeasureSpec
.getMode(widthMeasureSpec
);
284 final int specSize
= MeasureSpec
.getSize(widthMeasureSpec
);
285 final int oldMeasuredWidth
= getMeasuredWidth();
286 final int targetWidth
= widthMode
== MeasureSpec
.AT_MOST ? Math
.min(specSize
, mMinWidth
)
289 if (widthMode
!= MeasureSpec
.EXACTLY
&& mMinWidth
> 0 && oldMeasuredWidth
< targetWidth
) {
290 // Remeasure at exactly the minimum width.
291 super.onMeasure(MeasureSpec
.makeMeasureSpec(targetWidth
, MeasureSpec
.EXACTLY
),