IconMenuItemView.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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
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.widget.TextView;
30
31/**
32 * The item view for each item in the {@link IconMenuView}.
33 */
34public final class IconMenuItemView extends TextView implements MenuView.ItemView {
35
36    private static final int NO_ALPHA = 0xFF;
37
38    private IconMenuView mIconMenuView;
39
40    private ItemInvoker mItemInvoker;
41    private MenuItemImpl mItemData;
42
43    private Drawable mIcon;
44
45    private int mTextAppearance;
46    private Context mTextAppearanceContext;
47
48    private float mDisabledAlpha;
49
50    private Rect mPositionIconAvailable = new Rect();
51    private Rect mPositionIconOutput = new Rect();
52
53    private boolean mShortcutCaptionMode;
54    private String mShortcutCaption;
55
56    private static String sPrependShortcutLabel;
57
58    public IconMenuItemView(Context context, AttributeSet attrs, int defStyle) {
59        super(context, attrs);
60
61        if (sPrependShortcutLabel == null) {
62            /*
63             * Views should only be constructed from the UI thread, so no
64             * synchronization needed
65             */
66            sPrependShortcutLabel = getResources().getString(
67                    com.android.internal.R.string.prepend_shortcut_label);
68        }
69
70        TypedArray a =
71            context.obtainStyledAttributes(
72                attrs, com.android.internal.R.styleable.MenuView, defStyle, 0);
73
74        mDisabledAlpha = a.getFloat(
75                com.android.internal.R.styleable.MenuView_itemIconDisabledAlpha, 0.8f);
76        mTextAppearance = a.getResourceId(com.android.internal.R.styleable.
77                                          MenuView_itemTextAppearance, -1);
78        mTextAppearanceContext = context;
79
80        a.recycle();
81    }
82
83    public IconMenuItemView(Context context, AttributeSet attrs) {
84        this(context, attrs, 0);
85    }
86
87    /**
88     * Initializes with the provided title and icon
89     * @param title The title of this item
90     * @param icon The icon of this item
91     */
92    void initialize(CharSequence title, Drawable icon) {
93        setClickable(true);
94        setFocusable(true);
95
96        if (mTextAppearance != -1) {
97            setTextAppearance(mTextAppearanceContext, mTextAppearance);
98        }
99
100        setTitle(title);
101        setIcon(icon);
102    }
103
104    public void initialize(MenuItemImpl itemData, int menuType) {
105        mItemData = itemData;
106
107        initialize(itemData.getTitleForItemView(this), itemData.getIcon());
108
109        setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
110        setEnabled(itemData.isEnabled());
111    }
112
113    @Override
114    public boolean performClick() {
115        // Let the view's click listener have top priority (the More button relies on this)
116        if (super.performClick()) {
117            return true;
118        }
119
120        if ((mItemInvoker != null) && (mItemInvoker.invokeItem(mItemData))) {
121            playSoundEffect(SoundEffectConstants.CLICK);
122            return true;
123        } else {
124            return false;
125        }
126    }
127
128    public void setTitle(CharSequence title) {
129
130        if (mShortcutCaptionMode) {
131            /*
132             * Don't set the title directly since it will replace the
133             * shortcut+title being shown. Instead, re-set the shortcut caption
134             * mode so the new title is shown.
135             */
136            setCaptionMode(true);
137
138        } else if (title != null) {
139            setText(title);
140        }
141    }
142
143    void setCaptionMode(boolean shortcut) {
144
145        mShortcutCaptionMode = shortcut;
146
147        /*
148         * If there is no item model, don't do any of the below (for example,
149         * the 'More' item doesn't have a model)
150         */
151        if (mItemData == null) {
152            return;
153        }
154
155        CharSequence text = mItemData.getTitleForItemView(this);
156
157        if (shortcut) {
158
159            if (mShortcutCaption == null) {
160                mShortcutCaption = mItemData.getShortcutLabel();
161            }
162
163            text = mShortcutCaption;
164        }
165
166        setText(text);
167    }
168
169    public void setIcon(Drawable icon) {
170        mIcon = icon;
171
172        if (icon != null) {
173
174            /* Set the bounds of the icon since setCompoundDrawables needs it. */
175            icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
176
177            // Set the compound drawables
178            setCompoundDrawables(null, icon, null, null);
179
180            /*
181             * Request a layout to reposition the icon. The positioning of icon
182             * depends on this TextView's line bounds, which is only available
183             * after a layout.
184             */
185            requestLayout();
186        } else {
187            setCompoundDrawables(null, null, null, null);
188        }
189    }
190
191    public void setItemInvoker(ItemInvoker itemInvoker) {
192        mItemInvoker = itemInvoker;
193    }
194
195    public MenuItemImpl getItemData() {
196        return mItemData;
197    }
198
199    @Override
200    public void setVisibility(int v) {
201        super.setVisibility(v);
202
203        if (mIconMenuView != null) {
204            // On visibility change, mark the IconMenuView to refresh itself eventually
205            mIconMenuView.markStaleChildren();
206        }
207    }
208
209    void setIconMenuView(IconMenuView iconMenuView) {
210        mIconMenuView = iconMenuView;
211    }
212
213    @Override
214    protected void drawableStateChanged() {
215        super.drawableStateChanged();
216
217        if (mItemData != null && mIcon != null) {
218            // When disabled, the not-focused state and the pressed state should
219            // drop alpha on the icon
220            final boolean isInAlphaState = !mItemData.isEnabled() && (isPressed() || !isFocused());
221            mIcon.setAlpha(isInAlphaState ? (int) (mDisabledAlpha * NO_ALPHA) : NO_ALPHA);
222        }
223    }
224
225    @Override
226    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
227        super.onLayout(changed, left, top, right, bottom);
228
229        positionIcon();
230    }
231
232    /**
233     * Positions the icon vertically (horizontal centering is taken care of by
234     * the TextView's gravity).
235     */
236    private void positionIcon() {
237
238        if (mIcon == null) {
239            return;
240        }
241
242        // We reuse the output rectangle as a temp rect
243        Rect tmpRect = mPositionIconOutput;
244        getLineBounds(0, tmpRect);
245        mPositionIconAvailable.set(0, 0, getWidth(), tmpRect.top);
246        Gravity.apply(Gravity.CENTER_VERTICAL | Gravity.LEFT, mIcon.getIntrinsicWidth(), mIcon
247                .getIntrinsicHeight(), mPositionIconAvailable, mPositionIconOutput);
248        mIcon.setBounds(mPositionIconOutput);
249    }
250
251    public void setCheckable(boolean checkable) {
252    }
253
254    public void setChecked(boolean checked) {
255    }
256
257    public void setShortcut(boolean showShortcut, char shortcutKey) {
258
259        if (mShortcutCaptionMode) {
260            /*
261             * Shortcut has changed and we're showing it right now, need to
262             * update (clear the old one first).
263             */
264            mShortcutCaption = null;
265            setCaptionMode(true);
266        }
267    }
268
269    public boolean prefersCondensedTitle() {
270        return true;
271    }
272
273    public boolean showsIcon() {
274        return true;
275    }
276
277}
278