• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.internal.view.menu;
18 
19 import com.android.internal.view.menu.MenuBuilder.ItemInvoker;
20 
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.util.AttributeSet;
26 import android.view.Gravity;
27 import android.view.SoundEffectConstants;
28 import android.view.View;
29 import android.view.ViewDebug;
30 import android.widget.TextView;
31 import android.text.Layout;
32 
33 /**
34  * The item view for each item in the {@link IconMenuView}.
35  */
36 public 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 
IconMenuItemView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)60     public IconMenuItemView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
61         super(context, attrs, defStyleAttr, defStyleRes);
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         final TypedArray a = context.obtainStyledAttributes(
73                 attrs, com.android.internal.R.styleable.MenuView, defStyleAttr, defStyleRes);
74 
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     }
83 
IconMenuItemView(Context context, AttributeSet attrs, int defStyleAttr)84     public IconMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
85         this(context, attrs, defStyleAttr, 0);
86     }
87 
IconMenuItemView(Context context, AttributeSet attrs)88     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      */
initialize(CharSequence title, Drawable icon)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 
initialize(MenuItemImpl itemData, int menuType)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 
setItemData(MenuItemImpl data)118     public void setItemData(MenuItemImpl data) {
119         mItemData = data;
120     }
121 
122     @Override
performClick()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 
setTitle(CharSequence title)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 
setCaptionMode(boolean shortcut)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 
setIcon(Drawable icon)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 
setItemInvoker(ItemInvoker itemInvoker)205     public void setItemInvoker(ItemInvoker itemInvoker) {
206         mItemInvoker = itemInvoker;
207     }
208 
209     @ViewDebug.CapturedViewProperty(retrieveReturn = true)
getItemData()210     public MenuItemImpl getItemData() {
211         return mItemData;
212     }
213 
214     @Override
setVisibility(int v)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 
setIconMenuView(IconMenuView iconMenuView)224     void setIconMenuView(IconMenuView iconMenuView) {
225         mIconMenuView = iconMenuView;
226     }
227 
228     @Override
drawableStateChanged()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
onLayout(boolean changed, int left, int top, int right, int bottom)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 
247     @Override
onTextChanged(CharSequence text, int start, int before, int after)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      */
getTextAppropriateLayoutParams()259     IconMenuView.LayoutParams getTextAppropriateLayoutParams() {
260         IconMenuView.LayoutParams lp = (IconMenuView.LayoutParams) getLayoutParams();
261         if (lp == null) {
262             // Default layout parameters
263             lp = new IconMenuView.LayoutParams(
264                     IconMenuView.LayoutParams.MATCH_PARENT, IconMenuView.LayoutParams.MATCH_PARENT);
265         }
266 
267         // Set the desired width of item
268         lp.desiredWidth = (int) Layout.getDesiredWidth(getText(), getPaint());
269 
270         return lp;
271     }
272 
273     /**
274      * Positions the icon vertically (horizontal centering is taken care of by
275      * the TextView's gravity).
276      */
positionIcon()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);
287         final int layoutDirection = getLayoutDirection();
288         Gravity.apply(Gravity.CENTER_VERTICAL | Gravity.START, mIcon.getIntrinsicWidth(), mIcon
289                 .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput,
290                 layoutDirection);
291         mIcon.setBounds(mPositionIconOutput);
292     }
293 
setCheckable(boolean checkable)294     public void setCheckable(boolean checkable) {
295     }
296 
setChecked(boolean checked)297     public void setChecked(boolean checked) {
298     }
299 
setShortcut(boolean showShortcut, char shortcutKey)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 
prefersCondensedTitle()312     public boolean prefersCondensedTitle() {
313         return true;
314     }
315 
showsIcon()316     public boolean showsIcon() {
317         return true;
318     }
319 
320 }
321