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