blob: de5e2798a7be73f17aa8fcbc14905943fd05b88e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
17package com.android.internal.view.menu;
18
19import com.android.internal.view.menu.MenuBuilder.ItemInvoker;
20
21import android.content.Context;
22import android.content.res.TypedArray;
23import android.graphics.Rect;
24import android.graphics.drawable.Drawable;
25import android.util.AttributeSet;
26import android.view.Gravity;
27import android.view.SoundEffectConstants;
28import android.view.View;
29import android.view.ViewDebug;
30import android.widget.TextView;
The Android Open Source Project10592532009-03-18 17:39:46 -070031import android.text.Layout;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
33/**
34 * The item view for each item in the {@link IconMenuView}.
35 */
36public final class IconMenuItemView extends TextView implements MenuView.ItemView {
37
38 private static final int NO_ALPHA = 0xFF;
39
40 private IconMenuView mIconMenuView;
41
42 private ItemInvoker mItemInvoker;
43 private MenuItemImpl mItemData;
44
45 private Drawable mIcon;
46
47 private int mTextAppearance;
48 private Context mTextAppearanceContext;
49
50 private float mDisabledAlpha;
51
52 private Rect mPositionIconAvailable = new Rect();
53 private Rect mPositionIconOutput = new Rect();
54
55 private boolean mShortcutCaptionMode;
56 private String mShortcutCaption;
57
58 private static String sPrependShortcutLabel;
59
Alan Viverette617feb92013-09-09 18:09:13 -070060 public IconMenuItemView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
61 super(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
63 if (sPrependShortcutLabel == null) {
64 /*
65 * Views should only be constructed from the UI thread, so no
66 * synchronization needed
67 */
68 sPrependShortcutLabel = getResources().getString(
69 com.android.internal.R.string.prepend_shortcut_label);
70 }
Alan Viverette617feb92013-09-09 18:09:13 -070071
72 final TypedArray a = context.obtainStyledAttributes(
73 attrs, com.android.internal.R.styleable.MenuView, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074
75 mDisabledAlpha = a.getFloat(
76 com.android.internal.R.styleable.MenuView_itemIconDisabledAlpha, 0.8f);
77 mTextAppearance = a.getResourceId(com.android.internal.R.styleable.
78 MenuView_itemTextAppearance, -1);
79 mTextAppearanceContext = context;
80
81 a.recycle();
82 }
Alan Viverette617feb92013-09-09 18:09:13 -070083
84 public IconMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
85 this(context, attrs, defStyleAttr, 0);
86 }
87
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 public IconMenuItemView(Context context, AttributeSet attrs) {
89 this(context, attrs, 0);
90 }
91
92 /**
93 * Initializes with the provided title and icon
94 * @param title The title of this item
95 * @param icon The icon of this item
96 */
97 void initialize(CharSequence title, Drawable icon) {
98 setClickable(true);
99 setFocusable(true);
100
101 if (mTextAppearance != -1) {
102 setTextAppearance(mTextAppearanceContext, mTextAppearance);
103 }
104
105 setTitle(title);
106 setIcon(icon);
107 }
108
109 public void initialize(MenuItemImpl itemData, int menuType) {
110 mItemData = itemData;
111
112 initialize(itemData.getTitleForItemView(this), itemData.getIcon());
113
114 setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
115 setEnabled(itemData.isEnabled());
116 }
117
Adam Powell696cba52011-03-29 10:38:16 -0700118 public void setItemData(MenuItemImpl data) {
119 mItemData = data;
120 }
121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 @Override
123 public boolean performClick() {
124 // Let the view's click listener have top priority (the More button relies on this)
125 if (super.performClick()) {
126 return true;
127 }
128
129 if ((mItemInvoker != null) && (mItemInvoker.invokeItem(mItemData))) {
130 playSoundEffect(SoundEffectConstants.CLICK);
131 return true;
132 } else {
133 return false;
134 }
135 }
136
137 public void setTitle(CharSequence title) {
138
139 if (mShortcutCaptionMode) {
140 /*
141 * Don't set the title directly since it will replace the
142 * shortcut+title being shown. Instead, re-set the shortcut caption
143 * mode so the new title is shown.
144 */
145 setCaptionMode(true);
146
147 } else if (title != null) {
148 setText(title);
149 }
150 }
151
152 void setCaptionMode(boolean shortcut) {
153 /*
154 * If there is no item model, don't do any of the below (for example,
155 * the 'More' item doesn't have a model)
156 */
157 if (mItemData == null) {
158 return;
159 }
160
161 mShortcutCaptionMode = shortcut && (mItemData.shouldShowShortcut());
162
163 CharSequence text = mItemData.getTitleForItemView(this);
164
165 if (mShortcutCaptionMode) {
166
167 if (mShortcutCaption == null) {
168 mShortcutCaption = mItemData.getShortcutLabel();
169 }
170
171 text = mShortcutCaption;
172 }
173
174 setText(text);
175 }
176
177 public void setIcon(Drawable icon) {
178 mIcon = icon;
179
180 if (icon != null) {
181
182 /* Set the bounds of the icon since setCompoundDrawables needs it. */
183 icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
184
185 // Set the compound drawables
186 setCompoundDrawables(null, icon, null, null);
187
188 // When there is an icon, make sure the text is at the bottom
189 setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
190
191 /*
192 * Request a layout to reposition the icon. The positioning of icon
193 * depends on this TextView's line bounds, which is only available
194 * after a layout.
195 */
196 requestLayout();
197 } else {
198 setCompoundDrawables(null, null, null, null);
199
200 // When there is no icon, make sure the text is centered vertically
201 setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
202 }
203 }
204
205 public void setItemInvoker(ItemInvoker itemInvoker) {
206 mItemInvoker = itemInvoker;
207 }
208
209 @ViewDebug.CapturedViewProperty(retrieveReturn = true)
210 public MenuItemImpl getItemData() {
211 return mItemData;
212 }
213
214 @Override
215 public void setVisibility(int v) {
216 super.setVisibility(v);
217
218 if (mIconMenuView != null) {
219 // On visibility change, mark the IconMenuView to refresh itself eventually
220 mIconMenuView.markStaleChildren();
221 }
222 }
223
224 void setIconMenuView(IconMenuView iconMenuView) {
225 mIconMenuView = iconMenuView;
226 }
227
228 @Override
229 protected void drawableStateChanged() {
230 super.drawableStateChanged();
231
232 if (mItemData != null && mIcon != null) {
233 // When disabled, the not-focused state and the pressed state should
234 // drop alpha on the icon
235 final boolean isInAlphaState = !mItemData.isEnabled() && (isPressed() || !isFocused());
236 mIcon.setAlpha(isInAlphaState ? (int) (mDisabledAlpha * NO_ALPHA) : NO_ALPHA);
237 }
238 }
239
240 @Override
241 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
242 super.onLayout(changed, left, top, right, bottom);
243
244 positionIcon();
245 }
246
The Android Open Source Project10592532009-03-18 17:39:46 -0700247 @Override
248 protected void onTextChanged(CharSequence text, int start, int before, int after) {
249 super.onTextChanged(text, start, before, after);
250
251 // our layout params depend on the length of the text
252 setLayoutParams(getTextAppropriateLayoutParams());
253 }
254
255 /**
256 * @return layout params appropriate for this view. If layout params already exist, it will
257 * augment them to be appropriate to the current text size.
258 */
259 IconMenuView.LayoutParams getTextAppropriateLayoutParams() {
260 IconMenuView.LayoutParams lp = (IconMenuView.LayoutParams) getLayoutParams();
261 if (lp == null) {
262 // Default layout parameters
263 lp = new IconMenuView.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -0800264 IconMenuView.LayoutParams.MATCH_PARENT, IconMenuView.LayoutParams.MATCH_PARENT);
The Android Open Source Project10592532009-03-18 17:39:46 -0700265 }
266
267 // Set the desired width of item
268 lp.desiredWidth = (int) Layout.getDesiredWidth(getText(), getPaint());
269
270 return lp;
271 }
272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 /**
274 * Positions the icon vertically (horizontal centering is taken care of by
275 * the TextView's gravity).
276 */
277 private void positionIcon() {
278
279 if (mIcon == null) {
280 return;
281 }
282
283 // We reuse the output rectangle as a temp rect
284 Rect tmpRect = mPositionIconOutput;
285 getLineBounds(0, tmpRect);
286 mPositionIconAvailable.set(0, 0, getWidth(), tmpRect.top);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700287 final int layoutDirection = getLayoutDirection();
Fabrice Di Meglioaac0d4e2012-07-19 19:21:26 -0700288 Gravity.apply(Gravity.CENTER_VERTICAL | Gravity.START, mIcon.getIntrinsicWidth(), mIcon
Fabrice Di Meglioc0053222011-06-13 12:16:51 -0700289 .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput,
290 layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 mIcon.setBounds(mPositionIconOutput);
292 }
293
294 public void setCheckable(boolean checkable) {
295 }
296
297 public void setChecked(boolean checked) {
298 }
299
300 public void setShortcut(boolean showShortcut, char shortcutKey) {
301
302 if (mShortcutCaptionMode) {
303 /*
304 * Shortcut has changed and we're showing it right now, need to
305 * update (clear the old one first).
306 */
307 mShortcutCaption = null;
308 setCaptionMode(true);
309 }
310 }
311
312 public boolean prefersCondensedTitle() {
313 return true;
314 }
315
316 public boolean showsIcon() {
317 return true;
318 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320}