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 17 package com.android.internal.view.menu; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.content.DialogInterface; 23 import android.os.IBinder; 24 import android.view.KeyEvent; 25 import android.view.View; 26 import android.view.Window; 27 import android.view.WindowManager; 28 29 /** 30 * Presents a menu as a modal dialog. 31 */ 32 public class MenuDialogHelper implements MenuHelper, DialogInterface.OnKeyListener, 33 DialogInterface.OnClickListener, DialogInterface.OnDismissListener, 34 MenuPresenter.Callback { 35 private MenuBuilder mMenu; 36 private AlertDialog mDialog; 37 ListMenuPresenter mPresenter; 38 private MenuPresenter.Callback mPresenterCallback; 39 40 @UnsupportedAppUsage MenuDialogHelper(MenuBuilder menu)41 public MenuDialogHelper(MenuBuilder menu) { 42 mMenu = menu; 43 } 44 45 /** 46 * Shows menu as a dialog. 47 * 48 * @param windowToken Optional token to assign to the window. 49 */ 50 @UnsupportedAppUsage show(IBinder windowToken)51 public void show(IBinder windowToken) { 52 // Many references to mMenu, create local reference 53 final MenuBuilder menu = mMenu; 54 55 // Get the builder for the dialog 56 final AlertDialog.Builder builder = new AlertDialog.Builder(menu.getContext()); 57 58 mPresenter = new ListMenuPresenter(builder.getContext(), 59 com.android.internal.R.layout.list_menu_item_layout); 60 61 mPresenter.setCallback(this); 62 mMenu.addMenuPresenter(mPresenter); 63 builder.setAdapter(mPresenter.getAdapter(), this); 64 65 // Set the title 66 final View headerView = menu.getHeaderView(); 67 if (headerView != null) { 68 // Menu's client has given a custom header view, use it 69 builder.setCustomTitle(headerView); 70 } else { 71 // Otherwise use the (text) title and icon 72 builder.setIcon(menu.getHeaderIcon()).setTitle(menu.getHeaderTitle()); 73 } 74 75 // Set the key listener 76 builder.setOnKeyListener(this); 77 78 // Show the menu 79 mDialog = builder.create(); 80 mDialog.setOnDismissListener(this); 81 82 WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); 83 lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 84 if (windowToken != null) { 85 lp.token = windowToken; 86 } 87 lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 88 89 mDialog.show(); 90 } 91 onKey(DialogInterface dialog, int keyCode, KeyEvent event)92 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { 93 if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_BACK) { 94 if (event.getAction() == KeyEvent.ACTION_DOWN 95 && event.getRepeatCount() == 0) { 96 Window win = mDialog.getWindow(); 97 if (win != null) { 98 View decor = win.getDecorView(); 99 if (decor != null) { 100 KeyEvent.DispatcherState ds = decor.getKeyDispatcherState(); 101 if (ds != null) { 102 ds.startTracking(event, this); 103 return true; 104 } 105 } 106 } 107 } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled()) { 108 Window win = mDialog.getWindow(); 109 if (win != null) { 110 View decor = win.getDecorView(); 111 if (decor != null) { 112 KeyEvent.DispatcherState ds = decor.getKeyDispatcherState(); 113 if (ds != null && ds.isTracking(event)) { 114 mMenu.close(true /* closeAllMenus */); 115 dialog.dismiss(); 116 return true; 117 } 118 } 119 } 120 } 121 } 122 123 // Menu shortcut matching 124 return mMenu.performShortcut(keyCode, event, 0); 125 126 } 127 128 @Override setPresenterCallback(MenuPresenter.Callback cb)129 public void setPresenterCallback(MenuPresenter.Callback cb) { 130 mPresenterCallback = cb; 131 } 132 133 /** 134 * Dismisses the menu's dialog. 135 * 136 * @see Dialog#dismiss() 137 */ 138 @UnsupportedAppUsage 139 @Override dismiss()140 public void dismiss() { 141 if (mDialog != null) { 142 mDialog.dismiss(); 143 } 144 } 145 146 @Override onDismiss(DialogInterface dialog)147 public void onDismiss(DialogInterface dialog) { 148 mPresenter.onCloseMenu(mMenu, true); 149 } 150 151 @Override onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing)152 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 153 if (allMenusAreClosing || menu == mMenu) { 154 dismiss(); 155 } 156 if (mPresenterCallback != null) { 157 mPresenterCallback.onCloseMenu(menu, allMenusAreClosing); 158 } 159 } 160 161 @Override onOpenSubMenu(MenuBuilder subMenu)162 public boolean onOpenSubMenu(MenuBuilder subMenu) { 163 if (mPresenterCallback != null) { 164 return mPresenterCallback.onOpenSubMenu(subMenu); 165 } 166 return false; 167 } 168 onClick(DialogInterface dialog, int which)169 public void onClick(DialogInterface dialog, int which) { 170 mMenu.performItemAction((MenuItemImpl) mPresenter.getAdapter().getItem(which), 0); 171 } 172 } 173