1 /* 2 * Copyright (C) 2012 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.util.Log; 27 import android.view.ContextMenu; 28 import android.view.MenuItem; 29 import android.view.SubMenu; 30 import android.view.View; 31 import android.widget.FrameLayout; 32 33 import androidx.annotation.RestrictTo; 34 import androidx.appcompat.view.CollapsibleActionView; 35 import androidx.core.internal.view.SupportMenuItem; 36 import androidx.core.view.ActionProvider; 37 38 import java.lang.reflect.Method; 39 40 /** 41 * Wraps a support {@link SupportMenuItem} as a framework {@link android.view.MenuItem} 42 * @hide 43 */ 44 @RestrictTo(LIBRARY_GROUP) 45 public class MenuItemWrapperICS extends BaseMenuWrapper<SupportMenuItem> implements MenuItem { 46 static final String LOG_TAG = "MenuItemWrapper"; 47 48 // Reflection Method to call setExclusiveCheckable 49 private Method mSetExclusiveCheckableMethod; 50 51 MenuItemWrapperICS(Context context, SupportMenuItem object) { 52 super(context, object); 53 } 54 55 @Override 56 public int getItemId() { 57 return mWrappedObject.getItemId(); 58 } 59 60 @Override 61 public int getGroupId() { 62 return mWrappedObject.getGroupId(); 63 } 64 65 @Override 66 public int getOrder() { 67 return mWrappedObject.getOrder(); 68 } 69 70 @Override 71 public MenuItem setTitle(CharSequence title) { 72 mWrappedObject.setTitle(title); 73 return this; 74 } 75 76 @Override 77 public MenuItem setTitle(int title) { 78 mWrappedObject.setTitle(title); 79 return this; 80 } 81 82 @Override 83 public CharSequence getTitle() { 84 return mWrappedObject.getTitle(); 85 } 86 87 @Override 88 public MenuItem setTitleCondensed(CharSequence title) { 89 mWrappedObject.setTitleCondensed(title); 90 return this; 91 } 92 93 @Override 94 public CharSequence getTitleCondensed() { 95 return mWrappedObject.getTitleCondensed(); 96 } 97 98 @Override 99 public MenuItem setIcon(Drawable icon) { 100 mWrappedObject.setIcon(icon); 101 return this; 102 } 103 104 @Override 105 public MenuItem setIcon(int iconRes) { 106 mWrappedObject.setIcon(iconRes); 107 return this; 108 } 109 110 @Override 111 public Drawable getIcon() { 112 return mWrappedObject.getIcon(); 113 } 114 115 @Override 116 public MenuItem setIntent(Intent intent) { 117 mWrappedObject.setIntent(intent); 118 return this; 119 } 120 121 @Override 122 public Intent getIntent() { 123 return mWrappedObject.getIntent(); 124 } 125 126 @Override 127 public MenuItem setShortcut(char numericChar, char alphaChar) { 128 mWrappedObject.setShortcut(numericChar, alphaChar); 129 return this; 130 } 131 132 @Override 133 public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers, 134 int alphaModifiers) { 135 mWrappedObject.setShortcut(numericChar, alphaChar, numericModifiers, alphaModifiers); 136 return this; 137 } 138 139 @Override 140 public MenuItem setNumericShortcut(char numericChar) { 141 mWrappedObject.setNumericShortcut(numericChar); 142 return this; 143 } 144 145 @Override 146 public MenuItem setNumericShortcut(char numericChar, int numericModifiers) { 147 mWrappedObject.setNumericShortcut(numericChar, numericModifiers); 148 return this; 149 } 150 151 @Override 152 public char getNumericShortcut() { 153 return mWrappedObject.getNumericShortcut(); 154 } 155 156 @Override 157 public int getNumericModifiers() { 158 return mWrappedObject.getNumericModifiers(); 159 } 160 161 @Override 162 public MenuItem setAlphabeticShortcut(char alphaChar) { 163 mWrappedObject.setAlphabeticShortcut(alphaChar); 164 return this; 165 } 166 167 @Override 168 public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) { 169 mWrappedObject.setAlphabeticShortcut(alphaChar, alphaModifiers); 170 return this; 171 } 172 173 @Override 174 public char getAlphabeticShortcut() { 175 return mWrappedObject.getAlphabeticShortcut(); 176 } 177 178 @Override 179 public int getAlphabeticModifiers() { 180 return mWrappedObject.getAlphabeticModifiers(); 181 } 182 183 @Override 184 public MenuItem setCheckable(boolean checkable) { 185 mWrappedObject.setCheckable(checkable); 186 return this; 187 } 188 189 @Override 190 public boolean isCheckable() { 191 return mWrappedObject.isCheckable(); 192 } 193 194 @Override 195 public MenuItem setChecked(boolean checked) { 196 mWrappedObject.setChecked(checked); 197 return this; 198 } 199 200 @Override 201 public boolean isChecked() { 202 return mWrappedObject.isChecked(); 203 } 204 205 @Override 206 public MenuItem setVisible(boolean visible) { 207 return mWrappedObject.setVisible(visible); 208 } 209 210 @Override 211 public boolean isVisible() { 212 return mWrappedObject.isVisible(); 213 } 214 215 @Override 216 public MenuItem setEnabled(boolean enabled) { 217 mWrappedObject.setEnabled(enabled); 218 return this; 219 } 220 221 @Override 222 public boolean isEnabled() { 223 return mWrappedObject.isEnabled(); 224 } 225 226 @Override 227 public boolean hasSubMenu() { 228 return mWrappedObject.hasSubMenu(); 229 } 230 231 @Override 232 public SubMenu getSubMenu() { 233 return getSubMenuWrapper(mWrappedObject.getSubMenu()); 234 } 235 236 @Override 237 public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) { 238 mWrappedObject.setOnMenuItemClickListener(menuItemClickListener != null ? 239 new OnMenuItemClickListenerWrapper(menuItemClickListener) : null); 240 return this; 241 } 242 243 @Override 244 public ContextMenu.ContextMenuInfo getMenuInfo() { 245 return mWrappedObject.getMenuInfo(); 246 } 247 248 @Override 249 public void setShowAsAction(int actionEnum) { 250 mWrappedObject.setShowAsAction(actionEnum); 251 } 252 253 @Override 254 public MenuItem setShowAsActionFlags(int actionEnum) { 255 mWrappedObject.setShowAsActionFlags(actionEnum); 256 return this; 257 } 258 259 @Override 260 public MenuItem setActionView(View view) { 261 if (view instanceof android.view.CollapsibleActionView) { 262 view = new CollapsibleActionViewWrapper(view); 263 } 264 mWrappedObject.setActionView(view); 265 return this; 266 } 267 268 @Override 269 public MenuItem setActionView(int resId) { 270 // Make framework menu item inflate the view 271 mWrappedObject.setActionView(resId); 272 273 View actionView = mWrappedObject.getActionView(); 274 if (actionView instanceof android.view.CollapsibleActionView) { 275 // If the inflated Action View is support-collapsible, wrap it 276 mWrappedObject.setActionView(new CollapsibleActionViewWrapper(actionView)); 277 } 278 return this; 279 } 280 281 @Override 282 public View getActionView() { 283 View actionView = mWrappedObject.getActionView(); 284 if (actionView instanceof CollapsibleActionViewWrapper) { 285 return ((CollapsibleActionViewWrapper) actionView).getWrappedView(); 286 } 287 return actionView; 288 } 289 290 @Override 291 public MenuItem setActionProvider(android.view.ActionProvider provider) { 292 mWrappedObject.setSupportActionProvider( 293 provider != null ? createActionProviderWrapper(provider) : null); 294 return this; 295 } 296 297 @Override 298 public android.view.ActionProvider getActionProvider() { 299 ActionProvider provider = mWrappedObject.getSupportActionProvider(); 300 if (provider instanceof ActionProviderWrapper) { 301 return ((ActionProviderWrapper) provider).mInner; 302 } 303 return null; 304 } 305 306 @Override 307 public boolean expandActionView() { 308 return mWrappedObject.expandActionView(); 309 } 310 311 @Override 312 public boolean collapseActionView() { 313 return mWrappedObject.collapseActionView(); 314 } 315 316 @Override 317 public boolean isActionViewExpanded() { 318 return mWrappedObject.isActionViewExpanded(); 319 } 320 321 @Override 322 public MenuItem setOnActionExpandListener(MenuItem.OnActionExpandListener listener) { 323 mWrappedObject.setOnActionExpandListener(listener != null 324 ? new OnActionExpandListenerWrapper(listener) : null); 325 return this; 326 } 327 328 @Override 329 public MenuItem setContentDescription(CharSequence contentDescription) { 330 mWrappedObject.setContentDescription(contentDescription); 331 return this; 332 } 333 334 @Override 335 public CharSequence getContentDescription() { 336 return mWrappedObject.getContentDescription(); 337 } 338 339 @Override 340 public MenuItem setTooltipText(CharSequence tooltipText) { 341 mWrappedObject.setTooltipText(tooltipText); 342 return this; 343 } 344 345 @Override 346 public CharSequence getTooltipText() { 347 return mWrappedObject.getTooltipText(); 348 } 349 350 @Override 351 public MenuItem setIconTintList(ColorStateList tint) { 352 mWrappedObject.setIconTintList(tint); 353 return this; 354 } 355 356 @Override 357 public ColorStateList getIconTintList() { 358 return mWrappedObject.getIconTintList(); 359 } 360 361 @Override 362 public MenuItem setIconTintMode(PorterDuff.Mode tintMode) { 363 mWrappedObject.setIconTintMode(tintMode); 364 return this; 365 } 366 367 @Override 368 public PorterDuff.Mode getIconTintMode() { 369 return mWrappedObject.getIconTintMode(); 370 } 371 372 public void setExclusiveCheckable(boolean checkable) { 373 try { 374 if (mSetExclusiveCheckableMethod == null) { 375 mSetExclusiveCheckableMethod = mWrappedObject.getClass() 376 .getDeclaredMethod("setExclusiveCheckable", Boolean.TYPE); 377 } 378 mSetExclusiveCheckableMethod.invoke(mWrappedObject, checkable); 379 } catch (Exception e) { 380 Log.w(LOG_TAG, "Error while calling setExclusiveCheckable", e); 381 } 382 } 383 384 ActionProviderWrapper createActionProviderWrapper(android.view.ActionProvider provider) { 385 return new ActionProviderWrapper(mContext, provider); 386 } 387 388 private class OnMenuItemClickListenerWrapper extends BaseWrapper<OnMenuItemClickListener> 389 implements android.view.MenuItem.OnMenuItemClickListener { 390 391 OnMenuItemClickListenerWrapper(OnMenuItemClickListener object) { 392 super(object); 393 } 394 395 @Override 396 public boolean onMenuItemClick(android.view.MenuItem item) { 397 return mWrappedObject.onMenuItemClick(getMenuItemWrapper(item)); 398 } 399 } 400 401 private class OnActionExpandListenerWrapper extends BaseWrapper<MenuItem.OnActionExpandListener> 402 implements MenuItem.OnActionExpandListener { 403 404 OnActionExpandListenerWrapper(MenuItem.OnActionExpandListener object) { 405 super(object); 406 } 407 408 @Override 409 public boolean onMenuItemActionExpand(android.view.MenuItem item) { 410 return mWrappedObject.onMenuItemActionExpand(getMenuItemWrapper(item)); 411 } 412 413 @Override 414 public boolean onMenuItemActionCollapse(android.view.MenuItem item) { 415 return mWrappedObject.onMenuItemActionCollapse(getMenuItemWrapper(item)); 416 } 417 } 418 419 class ActionProviderWrapper extends androidx.core.view.ActionProvider { 420 final android.view.ActionProvider mInner; 421 422 public ActionProviderWrapper(Context context, android.view.ActionProvider inner) { 423 super(context); 424 mInner = inner; 425 } 426 427 @Override 428 public View onCreateActionView() { 429 return mInner.onCreateActionView(); 430 } 431 432 @Override 433 public boolean onPerformDefaultAction() { 434 return mInner.onPerformDefaultAction(); 435 } 436 437 @Override 438 public boolean hasSubMenu() { 439 return mInner.hasSubMenu(); 440 } 441 442 @Override 443 public void onPrepareSubMenu(android.view.SubMenu subMenu) { 444 mInner.onPrepareSubMenu(getSubMenuWrapper(subMenu)); 445 } 446 } 447 448 /** 449 * Wrap a support {@link androidx.appcompat.view.CollapsibleActionView} into a framework 450 * {@link android.view.CollapsibleActionView}. 451 */ 452 static class CollapsibleActionViewWrapper extends FrameLayout 453 implements CollapsibleActionView { 454 455 final android.view.CollapsibleActionView mWrappedView; 456 457 CollapsibleActionViewWrapper(View actionView) { 458 super(actionView.getContext()); 459 mWrappedView = (android.view.CollapsibleActionView) actionView; 460 addView(actionView); 461 } 462 463 @Override 464 public void onActionViewExpanded() { 465 mWrappedView.onActionViewExpanded(); 466 } 467 468 @Override 469 public void onActionViewCollapsed() { 470 mWrappedView.onActionViewCollapsed(); 471 } 472 473 View getWrappedView() { 474 return (View) mWrappedView; 475 } 476 } 477 } 478