blob: afa8a01e2f96441cd25f9f6486d1db5d62361a53 [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
60 public IconMenuItemView(Context context, AttributeSet attrs, int defStyle) {
61 super(context, attrs);
62
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 }
71
72 TypedArray a =
73 context.obtainStyledAttributes(
74 attrs, com.android.internal.R.styleable.MenuView, defStyle, 0);
75
76 mDisabledAlpha = a.getFloat(
77 com.android.internal.R.styleable.MenuView_itemIconDisabledAlpha, 0.8f);
78 mTextAppearance = a.getResourceId(com.android.internal.R.styleable.
79 MenuView_itemTextAppearance, -1);
80 mTextAppearanceContext = context;
81
82 a.recycle();
83 }
84
85 public IconMenuItemView(Context context, AttributeSet attrs) {
86 this(context, attrs, 0);
87 }
88
89 /**
90 * Initializes with the provided title and icon
91 * @param title The title of this item
92 * @param icon The icon of this item
93 */
94 void initialize(CharSequence title, Drawable icon) {
95 setClickable(true);
96 setFocusable(true);
97
98 if (mTextAppearance != -1) {
99 setTextAppearance(mTextAppearanceContext, mTextAppearance);
100 }
101
102 setTitle(title);
103 setIcon(icon);
104 }
105
106 public void initialize(MenuItemImpl itemData, int menuType) {
107 mItemData = itemData;
108
109 initialize(itemData.getTitleForItemView(this), itemData.getIcon());
110
111 setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
112 setEnabled(itemData.isEnabled());
113 }
114
Adam Powell696cba52011-03-29 10:38:16 -0700115 public void setItemData(MenuItemImpl data) {
116 mItemData = data;
117 }
118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 @Override
120 public boolean performClick() {
121 // Let the view's click listener have top priority (the More button relies on this)
122 if (super.performClick()) {
123 return true;
124 }
125
126 if ((mItemInvoker != null) && (mItemInvoker.invokeItem(mItemData))) {
127 playSoundEffect(SoundEffectConstants.CLICK);
128 return true;
129 } else {
130 return false;
131 }
132 }
133
134 public void setTitle(CharSequence title) {
135
136 if (mShortcutCaptionMode) {
137 /*
138 * Don't set the title directly since it will replace the
139 * shortcut+title being shown. Instead, re-set the shortcut caption
140 * mode so the new title is shown.
141 */
142 setCaptionMode(true);
143
144 } else if (title != null) {
145 setText(title);
146 }
147 }
148
149 void setCaptionMode(boolean shortcut) {
150 /*
151 * If there is no item model, don't do any of the below (for example,
152 * the 'More' item doesn't have a model)
153 */
154 if (mItemData == null) {
155 return;
156 }
157
158 mShortcutCaptionMode = shortcut && (mItemData.shouldShowShortcut());
159
160 CharSequence text = mItemData.getTitleForItemView(this);
161
162 if (mShortcutCaptionMode) {
163
164 if (mShortcutCaption == null) {
165 mShortcutCaption = mItemData.getShortcutLabel();
166 }
167
168 text = mShortcutCaption;
169 }
170
171 setText(text);
172 }
173
174 public void setIcon(Drawable icon) {
175 mIcon = icon;
176
177 if (icon != null) {
178
179 /* Set the bounds of the icon since setCompoundDrawables needs it. */
180 icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
181
182 // Set the compound drawables
183 setCompoundDrawables(null, icon, null, null);
184
185 // When there is an icon, make sure the text is at the bottom
186 setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
187
188 /*
189 * Request a layout to reposition the icon. The positioning of icon
190 * depends on this TextView's line bounds, which is only available
191 * after a layout.
192 */
193 requestLayout();
194 } else {
195 setCompoundDrawables(null, null, null, null);
196
197 // When there is no icon, make sure the text is centered vertically
198 setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
199 }
200 }
201
202 public void setItemInvoker(ItemInvoker itemInvoker) {
203 mItemInvoker = itemInvoker;
204 }
205
206 @ViewDebug.CapturedViewProperty(retrieveReturn = true)
207 public MenuItemImpl getItemData() {
208 return mItemData;
209 }
210
211 @Override
212 public void setVisibility(int v) {
213 super.setVisibility(v);
214
215 if (mIconMenuView != null) {
216 // On visibility change, mark the IconMenuView to refresh itself eventually
217 mIconMenuView.markStaleChildren();
218 }
219 }
220
221 void setIconMenuView(IconMenuView iconMenuView) {
222 mIconMenuView = iconMenuView;
223 }
224
225 @Override
226 protected void drawableStateChanged() {
227 super.drawableStateChanged();
228
229 if (mItemData != null && mIcon != null) {
230 // When disabled, the not-focused state and the pressed state should
231 // drop alpha on the icon
232 final boolean isInAlphaState = !mItemData.isEnabled() && (isPressed() || !isFocused());
233 mIcon.setAlpha(isInAlphaState ? (int) (mDisabledAlpha * NO_ALPHA) : NO_ALPHA);
234 }
235 }
236
237 @Override
238 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
239 super.onLayout(changed, left, top, right, bottom);
240
241 positionIcon();
242 }
243
The Android Open Source Project10592532009-03-18 17:39:46 -0700244 @Override
245 protected void onTextChanged(CharSequence text, int start, int before, int after) {
246 super.onTextChanged(text, start, before, after);
247
248 // our layout params depend on the length of the text
249 setLayoutParams(getTextAppropriateLayoutParams());
250 }
251
252 /**
253 * @return layout params appropriate for this view. If layout params already exist, it will
254 * augment them to be appropriate to the current text size.
255 */
256 IconMenuView.LayoutParams getTextAppropriateLayoutParams() {
257 IconMenuView.LayoutParams lp = (IconMenuView.LayoutParams) getLayoutParams();
258 if (lp == null) {
259 // Default layout parameters
260 lp = new IconMenuView.LayoutParams(
Romain Guy980a9382010-01-08 15:06:28 -0800261 IconMenuView.LayoutParams.MATCH_PARENT, IconMenuView.LayoutParams.MATCH_PARENT);
The Android Open Source Project10592532009-03-18 17:39:46 -0700262 }
263
264 // Set the desired width of item
265 lp.desiredWidth = (int) Layout.getDesiredWidth(getText(), getPaint());
266
267 return lp;
268 }
269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 /**
271 * Positions the icon vertically (horizontal centering is taken care of by
272 * the TextView's gravity).
273 */
274 private void positionIcon() {
275
276 if (mIcon == null) {
277 return;
278 }
279
280 // We reuse the output rectangle as a temp rect
281 Rect tmpRect = mPositionIconOutput;
282 getLineBounds(0, tmpRect);
283 mPositionIconAvailable.set(0, 0, getWidth(), tmpRect.top);
284 Gravity.apply(Gravity.CENTER_VERTICAL | Gravity.LEFT, mIcon.getIntrinsicWidth(), mIcon
285 .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput);
286 mIcon.setBounds(mPositionIconOutput);
287 }
288
289 public void setCheckable(boolean checkable) {
290 }
291
292 public void setChecked(boolean checked) {
293 }
294
295 public void setShortcut(boolean showShortcut, char shortcutKey) {
296
297 if (mShortcutCaptionMode) {
298 /*
299 * Shortcut has changed and we're showing it right now, need to
300 * update (clear the old one first).
301 */
302 mShortcutCaption = null;
303 setCaptionMode(true);
304 }
305 }
306
307 public boolean prefersCondensedTitle() {
308 return true;
309 }
310
311 public boolean showsIcon() {
312 return true;
313 }
The Android Open Source Project10592532009-03-18 17:39:46 -0700314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315}