1 /*
2  * Copyright (C) 2010 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 android.annotation.Nullable;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.res.ColorStateList;
24 import android.graphics.PorterDuff;
25 import android.graphics.drawable.Drawable;
26 import android.os.Build;
27 import android.view.ActionProvider;
28 import android.view.ContextMenu.ContextMenuInfo;
29 import android.view.KeyEvent;
30 import android.view.MenuItem;
31 import android.view.SubMenu;
32 import android.view.View;
33 
34 /**
35  * @hide
36  */
37 public class ActionMenuItem implements MenuItem {
38     private final int mId;
39     private final int mGroup;
40     private final int mCategoryOrder;
41     private final int mOrdering;
42 
43     private CharSequence mTitle;
44     private CharSequence mTitleCondensed;
45     private Intent mIntent;
46     private char mShortcutNumericChar;
47     private int mShortcutNumericModifiers = KeyEvent.META_CTRL_ON;
48     private char mShortcutAlphabeticChar;
49     private int mShortcutAlphabeticModifiers = KeyEvent.META_CTRL_ON;
50 
51     private Drawable mIconDrawable;
52     private int mIconResId = NO_ICON;
53     private ColorStateList mIconTintList = null;
54     private PorterDuff.Mode mIconTintMode = null;
55     private boolean mHasIconTint = false;
56     private boolean mHasIconTintMode = false;
57 
58     private Context mContext;
59 
60     private MenuItem.OnMenuItemClickListener mClickListener;
61 
62     private CharSequence mContentDescription;
63     private CharSequence mTooltipText;
64 
65     private static final int NO_ICON = 0;
66 
67     private int mFlags = ENABLED;
68     private static final int CHECKABLE      = 0x00000001;
69     private static final int CHECKED        = 0x00000002;
70     private static final int EXCLUSIVE      = 0x00000004;
71     private static final int HIDDEN         = 0x00000008;
72     private static final int ENABLED        = 0x00000010;
73 
74     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering, CharSequence title)75     public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering,
76             CharSequence title) {
77         mContext = context;
78         mId = id;
79         mGroup = group;
80         mCategoryOrder = categoryOrder;
81         mOrdering = ordering;
82         mTitle = title;
83     }
84 
getAlphabeticShortcut()85     public char getAlphabeticShortcut() {
86         return mShortcutAlphabeticChar;
87     }
88 
getAlphabeticModifiers()89     public int getAlphabeticModifiers() {
90         return mShortcutAlphabeticModifiers;
91     }
92 
getGroupId()93     public int getGroupId() {
94         return mGroup;
95     }
96 
getIcon()97     public Drawable getIcon() {
98         return mIconDrawable;
99     }
100 
getIntent()101     public Intent getIntent() {
102         return mIntent;
103     }
104 
getItemId()105     public int getItemId() {
106         return mId;
107     }
108 
getMenuInfo()109     public ContextMenuInfo getMenuInfo() {
110         return null;
111     }
112 
getNumericShortcut()113     public char getNumericShortcut() {
114         return mShortcutNumericChar;
115     }
116 
getNumericModifiers()117     public int getNumericModifiers() {
118         return mShortcutNumericModifiers;
119     }
120 
getOrder()121     public int getOrder() {
122         return mOrdering;
123     }
124 
getSubMenu()125     public SubMenu getSubMenu() {
126         return null;
127     }
128 
getTitle()129     public CharSequence getTitle() {
130         return mTitle;
131     }
132 
getTitleCondensed()133     public CharSequence getTitleCondensed() {
134         return mTitleCondensed != null ? mTitleCondensed : mTitle;
135     }
136 
hasSubMenu()137     public boolean hasSubMenu() {
138         return false;
139     }
140 
isCheckable()141     public boolean isCheckable() {
142         return (mFlags & CHECKABLE) != 0;
143     }
144 
isChecked()145     public boolean isChecked() {
146         return (mFlags & CHECKED) != 0;
147     }
148 
isEnabled()149     public boolean isEnabled() {
150         return (mFlags & ENABLED) != 0;
151     }
152 
isVisible()153     public boolean isVisible() {
154         return (mFlags & HIDDEN) == 0;
155     }
156 
setAlphabeticShortcut(char alphaChar)157     public MenuItem setAlphabeticShortcut(char alphaChar) {
158         mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
159         return this;
160     }
161 
setAlphabeticShortcut(char alphachar, int alphaModifiers)162     public MenuItem setAlphabeticShortcut(char alphachar, int alphaModifiers) {
163         mShortcutAlphabeticChar = Character.toLowerCase(alphachar);
164         mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
165         return this;
166     }
167 
setCheckable(boolean checkable)168     public MenuItem setCheckable(boolean checkable) {
169         mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
170         return this;
171     }
172 
setExclusiveCheckable(boolean exclusive)173     public ActionMenuItem setExclusiveCheckable(boolean exclusive) {
174         mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
175         return this;
176     }
177 
setChecked(boolean checked)178     public MenuItem setChecked(boolean checked) {
179         mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
180         return this;
181     }
182 
setEnabled(boolean enabled)183     public MenuItem setEnabled(boolean enabled) {
184         mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0);
185         return this;
186     }
187 
setIcon(Drawable icon)188     public MenuItem setIcon(Drawable icon) {
189         mIconDrawable = icon;
190         mIconResId = NO_ICON;
191 
192         applyIconTint();
193         return this;
194     }
195 
setIcon(int iconRes)196     public MenuItem setIcon(int iconRes) {
197         mIconResId = iconRes;
198         mIconDrawable = mContext.getDrawable(iconRes);
199 
200         applyIconTint();
201         return this;
202     }
203 
204     @Override
setIconTintList(@ullable ColorStateList iconTintList)205     public MenuItem setIconTintList(@Nullable ColorStateList iconTintList) {
206         mIconTintList = iconTintList;
207         mHasIconTint = true;
208 
209         applyIconTint();
210 
211         return this;
212     }
213 
214     @Nullable
215     @Override
getIconTintList()216     public ColorStateList getIconTintList() {
217         return mIconTintList;
218     }
219 
220     @Override
setIconTintMode(PorterDuff.Mode iconTintMode)221     public MenuItem setIconTintMode(PorterDuff.Mode iconTintMode) {
222         mIconTintMode = iconTintMode;
223         mHasIconTintMode = true;
224 
225         applyIconTint();
226 
227         return this;
228     }
229 
230     @Nullable
231     @Override
getIconTintMode()232     public PorterDuff.Mode getIconTintMode() {
233         return mIconTintMode;
234     }
235 
applyIconTint()236     private void applyIconTint() {
237         if (mIconDrawable != null && (mHasIconTint || mHasIconTintMode)) {
238             mIconDrawable = mIconDrawable.mutate();
239 
240             if (mHasIconTint) {
241                 mIconDrawable.setTintList(mIconTintList);
242             }
243 
244             if (mHasIconTintMode) {
245                 mIconDrawable.setTintMode(mIconTintMode);
246             }
247         }
248     }
249 
setIntent(Intent intent)250     public MenuItem setIntent(Intent intent) {
251         mIntent = intent;
252         return this;
253     }
254 
setNumericShortcut(char numericChar)255     public MenuItem setNumericShortcut(char numericChar) {
256         mShortcutNumericChar = numericChar;
257         return this;
258     }
259 
setNumericShortcut(char numericChar, int numericModifiers)260     public MenuItem setNumericShortcut(char numericChar, int numericModifiers) {
261         mShortcutNumericChar = numericChar;
262         mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
263         return this;
264     }
265 
setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener)266     public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
267         mClickListener = menuItemClickListener;
268         return this;
269     }
270 
setShortcut(char numericChar, char alphaChar)271     public MenuItem setShortcut(char numericChar, char alphaChar) {
272         mShortcutNumericChar = numericChar;
273         mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
274         return this;
275     }
276 
setShortcut(char numericChar, char alphaChar, int numericModifiers, int alphaModifiers)277     public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers,
278             int alphaModifiers) {
279         mShortcutNumericChar = numericChar;
280         mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers);
281         mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
282         mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers);
283         return this;
284     }
285 
setTitle(CharSequence title)286     public MenuItem setTitle(CharSequence title) {
287         mTitle = title;
288         return this;
289     }
290 
setTitle(int title)291     public MenuItem setTitle(int title) {
292         mTitle = mContext.getResources().getString(title);
293         return this;
294     }
295 
setTitleCondensed(CharSequence title)296     public MenuItem setTitleCondensed(CharSequence title) {
297         mTitleCondensed = title;
298         return this;
299     }
300 
setVisible(boolean visible)301     public MenuItem setVisible(boolean visible) {
302         mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN);
303         return this;
304     }
305 
invoke()306     public boolean invoke() {
307         if (mClickListener != null && mClickListener.onMenuItemClick(this)) {
308             return true;
309         }
310 
311         if (mIntent != null) {
312             mContext.startActivity(mIntent);
313             return true;
314         }
315 
316         return false;
317     }
318 
setShowAsAction(int show)319     public void setShowAsAction(int show) {
320         // Do nothing. ActionMenuItems always show as action buttons.
321     }
322 
setActionView(View actionView)323     public MenuItem setActionView(View actionView) {
324         throw new UnsupportedOperationException();
325     }
326 
getActionView()327     public View getActionView() {
328         return null;
329     }
330 
331     @Override
setActionView(int resId)332     public MenuItem setActionView(int resId) {
333         throw new UnsupportedOperationException();
334     }
335 
336     @Override
getActionProvider()337     public ActionProvider getActionProvider() {
338         return null;
339     }
340 
341     @Override
setActionProvider(ActionProvider actionProvider)342     public MenuItem setActionProvider(ActionProvider actionProvider) {
343         throw new UnsupportedOperationException();
344     }
345 
346     @Override
setShowAsActionFlags(int actionEnum)347     public MenuItem setShowAsActionFlags(int actionEnum) {
348         setShowAsAction(actionEnum);
349         return this;
350     }
351 
352     @Override
expandActionView()353     public boolean expandActionView() {
354         return false;
355     }
356 
357     @Override
collapseActionView()358     public boolean collapseActionView() {
359         return false;
360     }
361 
362     @Override
isActionViewExpanded()363     public boolean isActionViewExpanded() {
364         return false;
365     }
366 
367     @Override
setOnActionExpandListener(OnActionExpandListener listener)368     public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
369         // No need to save the listener; ActionMenuItem does not support collapsing items.
370         return this;
371     }
372 
373     @Override
setContentDescription(CharSequence contentDescription)374     public MenuItem setContentDescription(CharSequence contentDescription) {
375         mContentDescription = contentDescription;
376         return this;
377     }
378 
379     @Override
getContentDescription()380     public CharSequence getContentDescription() {
381         return mContentDescription;
382     }
383 
384     @Override
setTooltipText(CharSequence tooltipText)385     public MenuItem setTooltipText(CharSequence tooltipText) {
386         mTooltipText = tooltipText;
387         return this;
388     }
389 
390     @Override
getTooltipText()391     public CharSequence getTooltipText() {
392         return mTooltipText;
393     }
394 }
395