1/* 2 * Copyright (C) 2017 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 android.support.wear.widget.drawer; 18 19import android.annotation.TargetApi; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.graphics.drawable.Drawable; 24import android.os.Build; 25import android.support.annotation.Nullable; 26import android.view.ActionProvider; 27import android.view.ContextMenu; 28import android.view.KeyEvent; 29import android.view.Menu; 30import android.view.MenuItem; 31import android.view.SubMenu; 32import android.view.View; 33 34import java.util.ArrayList; 35import java.util.List; 36 37@TargetApi(Build.VERSION_CODES.M) 38/* package */ class WearableActionDrawerMenu implements Menu { 39 40 private final Context mContext; 41 private final List<WearableActionDrawerMenuItem> mItems = new ArrayList<>(); 42 private final WearableActionDrawerMenuListener mListener; 43 private final WearableActionDrawerMenuItem.MenuItemChangedListener mItemChangedListener = 44 new WearableActionDrawerMenuItem.MenuItemChangedListener() { 45 @Override 46 public void itemChanged(WearableActionDrawerMenuItem item) { 47 for (int i = 0; i < mItems.size(); i++) { 48 if (mItems.get(i) == item) { 49 mListener.menuItemChanged(i); 50 } 51 } 52 } 53 }; 54 55 WearableActionDrawerMenu(Context context, WearableActionDrawerMenuListener listener) { 56 mContext = context; 57 mListener = listener; 58 } 59 60 @Override 61 public MenuItem add(CharSequence title) { 62 return add(0, 0, 0, title); 63 } 64 65 @Override 66 public MenuItem add(int titleRes) { 67 return add(0, 0, 0, titleRes); 68 } 69 70 @Override 71 public MenuItem add(int groupId, int itemId, int order, int titleRes) { 72 return add(groupId, itemId, order, mContext.getResources().getString(titleRes)); 73 } 74 75 @Override 76 public MenuItem add(int groupId, int itemId, int order, CharSequence title) { 77 WearableActionDrawerMenuItem item = 78 new WearableActionDrawerMenuItem(mContext, itemId, title, mItemChangedListener); 79 mItems.add(item); 80 mListener.menuItemAdded(mItems.size() - 1); 81 return item; 82 } 83 84 @Override 85 public void clear() { 86 mItems.clear(); 87 mListener.menuChanged(); 88 } 89 90 @Override 91 public void removeItem(int id) { 92 int index = findItemIndex(id); 93 if ((index < 0) || (index >= mItems.size())) { 94 return; 95 } 96 mItems.remove(index); 97 mListener.menuItemRemoved(index); 98 } 99 100 @Override 101 public MenuItem findItem(int id) { 102 int index = findItemIndex(id); 103 if ((index < 0) || (index >= mItems.size())) { 104 return null; 105 } 106 return mItems.get(index); 107 } 108 109 @Override 110 public int size() { 111 return mItems.size(); 112 } 113 114 @Override 115 @Nullable 116 public MenuItem getItem(int index) { 117 if ((index < 0) || (index >= mItems.size())) { 118 return null; 119 } 120 return mItems.get(index); 121 } 122 123 private int findItemIndex(int id) { 124 final List<WearableActionDrawerMenuItem> items = mItems; 125 final int itemCount = items.size(); 126 for (int i = 0; i < itemCount; i++) { 127 if (items.get(i).getItemId() == id) { 128 return i; 129 } 130 } 131 132 return -1; 133 } 134 135 @Override 136 public void close() { 137 throw new UnsupportedOperationException("close is not implemented"); 138 } 139 140 @Override 141 public SubMenu addSubMenu(CharSequence title) { 142 throw new UnsupportedOperationException("addSubMenu is not implemented"); 143 } 144 145 @Override 146 public SubMenu addSubMenu(int titleRes) { 147 throw new UnsupportedOperationException("addSubMenu is not implemented"); 148 } 149 150 @Override 151 public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) { 152 throw new UnsupportedOperationException("addSubMenu is not implemented"); 153 } 154 155 @Override 156 public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) { 157 throw new UnsupportedOperationException("addSubMenu is not implemented"); 158 } 159 160 @Override 161 public int addIntentOptions( 162 int groupId, 163 int itemId, 164 int order, 165 ComponentName caller, 166 Intent[] specifics, 167 Intent intent, 168 int flags, 169 MenuItem[] outSpecificItems) { 170 throw new UnsupportedOperationException("addIntentOptions is not implemented"); 171 } 172 173 @Override 174 public void removeGroup(int groupId) { 175 } 176 177 @Override 178 public void setGroupCheckable(int group, boolean checkable, boolean exclusive) { 179 throw new UnsupportedOperationException("setGroupCheckable is not implemented"); 180 } 181 182 @Override 183 public void setGroupVisible(int group, boolean visible) { 184 throw new UnsupportedOperationException("setGroupVisible is not implemented"); 185 } 186 187 @Override 188 public void setGroupEnabled(int group, boolean enabled) { 189 throw new UnsupportedOperationException("setGroupEnabled is not implemented"); 190 } 191 192 @Override 193 public boolean hasVisibleItems() { 194 return false; 195 } 196 197 @Override 198 public boolean performShortcut(int keyCode, KeyEvent event, int flags) { 199 throw new UnsupportedOperationException("performShortcut is not implemented"); 200 } 201 202 @Override 203 public boolean isShortcutKey(int keyCode, KeyEvent event) { 204 return false; 205 } 206 207 @Override 208 public boolean performIdentifierAction(int id, int flags) { 209 throw new UnsupportedOperationException("performIdentifierAction is not implemented"); 210 } 211 212 @Override 213 public void setQwertyMode(boolean isQwerty) { 214 } 215 216 /* package */ interface WearableActionDrawerMenuListener { 217 218 void menuItemChanged(int position); 219 220 void menuItemAdded(int position); 221 222 void menuItemRemoved(int position); 223 224 void menuChanged(); 225 } 226 227 public static final class WearableActionDrawerMenuItem implements MenuItem { 228 229 private final int mId; 230 231 private final Context mContext; 232 private final MenuItemChangedListener mItemChangedListener; 233 private CharSequence mTitle; 234 private Drawable mIconDrawable; 235 private MenuItem.OnMenuItemClickListener mClickListener; 236 237 WearableActionDrawerMenuItem( 238 Context context, int id, CharSequence title, MenuItemChangedListener listener) { 239 mContext = context; 240 mId = id; 241 mTitle = title; 242 mItemChangedListener = listener; 243 } 244 245 @Override 246 public int getItemId() { 247 return mId; 248 } 249 250 @Override 251 public MenuItem setTitle(CharSequence title) { 252 mTitle = title; 253 if (mItemChangedListener != null) { 254 mItemChangedListener.itemChanged(this); 255 } 256 return this; 257 } 258 259 @Override 260 public MenuItem setTitle(int title) { 261 return setTitle(mContext.getResources().getString(title)); 262 } 263 264 @Override 265 public CharSequence getTitle() { 266 return mTitle; 267 } 268 269 @Override 270 public MenuItem setIcon(Drawable icon) { 271 mIconDrawable = icon; 272 if (mItemChangedListener != null) { 273 mItemChangedListener.itemChanged(this); 274 } 275 return this; 276 } 277 278 @Override 279 public MenuItem setIcon(int iconRes) { 280 return setIcon(mContext.getResources().getDrawable(iconRes)); 281 } 282 283 @Override 284 public Drawable getIcon() { 285 return mIconDrawable; 286 } 287 288 @Override 289 public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) { 290 mClickListener = menuItemClickListener; 291 return this; 292 } 293 294 @Override 295 public int getGroupId() { 296 return 0; 297 } 298 299 @Override 300 public int getOrder() { 301 return 0; 302 } 303 304 @Override 305 public MenuItem setTitleCondensed(CharSequence title) { 306 return this; 307 } 308 309 @Override 310 public CharSequence getTitleCondensed() { 311 return null; 312 } 313 314 @Override 315 public MenuItem setIntent(Intent intent) { 316 throw new UnsupportedOperationException("setIntent is not implemented"); 317 } 318 319 @Override 320 public Intent getIntent() { 321 return null; 322 } 323 324 @Override 325 public MenuItem setShortcut(char numericChar, char alphaChar) { 326 throw new UnsupportedOperationException("setShortcut is not implemented"); 327 } 328 329 @Override 330 public MenuItem setNumericShortcut(char numericChar) { 331 return this; 332 } 333 334 @Override 335 public char getNumericShortcut() { 336 return 0; 337 } 338 339 @Override 340 public MenuItem setAlphabeticShortcut(char alphaChar) { 341 return this; 342 } 343 344 @Override 345 public char getAlphabeticShortcut() { 346 return 0; 347 } 348 349 @Override 350 public MenuItem setCheckable(boolean checkable) { 351 return this; 352 } 353 354 @Override 355 public boolean isCheckable() { 356 return false; 357 } 358 359 @Override 360 public MenuItem setChecked(boolean checked) { 361 return this; 362 } 363 364 @Override 365 public boolean isChecked() { 366 return false; 367 } 368 369 @Override 370 public MenuItem setVisible(boolean visible) { 371 return this; 372 } 373 374 @Override 375 public boolean isVisible() { 376 return false; 377 } 378 379 @Override 380 public MenuItem setEnabled(boolean enabled) { 381 return this; 382 } 383 384 @Override 385 public boolean isEnabled() { 386 return false; 387 } 388 389 @Override 390 public boolean hasSubMenu() { 391 return false; 392 } 393 394 @Override 395 public SubMenu getSubMenu() { 396 return null; 397 } 398 399 @Override 400 public ContextMenu.ContextMenuInfo getMenuInfo() { 401 return null; 402 } 403 404 @Override 405 public void setShowAsAction(int actionEnum) { 406 throw new UnsupportedOperationException("setShowAsAction is not implemented"); 407 } 408 409 @Override 410 public MenuItem setShowAsActionFlags(int actionEnum) { 411 throw new UnsupportedOperationException("setShowAsActionFlags is not implemented"); 412 } 413 414 @Override 415 public MenuItem setActionView(View view) { 416 throw new UnsupportedOperationException("setActionView is not implemented"); 417 } 418 419 @Override 420 public MenuItem setActionView(int resId) { 421 throw new UnsupportedOperationException("setActionView is not implemented"); 422 } 423 424 @Override 425 public View getActionView() { 426 return null; 427 } 428 429 @Override 430 public MenuItem setActionProvider(ActionProvider actionProvider) { 431 throw new UnsupportedOperationException("setActionProvider is not implemented"); 432 } 433 434 @Override 435 public ActionProvider getActionProvider() { 436 return null; 437 } 438 439 @Override 440 public boolean expandActionView() { 441 throw new UnsupportedOperationException("expandActionView is not implemented"); 442 } 443 444 @Override 445 public boolean collapseActionView() { 446 throw new UnsupportedOperationException("collapseActionView is not implemented"); 447 } 448 449 @Override 450 public boolean isActionViewExpanded() { 451 throw new UnsupportedOperationException("isActionViewExpanded is not implemented"); 452 } 453 454 @Override 455 public MenuItem setOnActionExpandListener(OnActionExpandListener listener) { 456 throw new UnsupportedOperationException("setOnActionExpandListener is not implemented"); 457 } 458 459 /** 460 * Invokes the item by calling the listener if set. 461 * 462 * @return true if the invocation was handled, false otherwise 463 */ 464 /* package */ boolean invoke() { 465 return mClickListener != null && mClickListener.onMenuItemClick(this); 466 467 } 468 469 private interface MenuItemChangedListener { 470 471 void itemChanged(WearableActionDrawerMenuItem item); 472 } 473 } 474} 475