18262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns/* 28262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * Copyright (C) 2013 The Android Open Source Project 38262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * 48262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * Licensed under the Apache License, Version 2.0 (the "License"); 58262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * you may not use this file except in compliance with the License. 68262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * You may obtain a copy of the License at 78262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * 88262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * http://www.apache.org/licenses/LICENSE-2.0 98262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * 108262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * Unless required by applicable law or agreed to in writing, software 118262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * distributed under the License is distributed on an "AS IS" BASIS, 128262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * See the License for the specific language governing permissions and 148262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * limitations under the License. 158262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns */ 168262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 17da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownpackage android.support.v7.internal.view.menu; 188262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 198262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johnsimport android.app.AlertDialog; 208262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johnsimport android.app.Dialog; 218262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johnsimport android.content.DialogInterface; 228262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johnsimport android.os.IBinder; 23da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.appcompat.R; 248262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johnsimport android.view.KeyEvent; 258262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johnsimport android.view.View; 268262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johnsimport android.view.Window; 278262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johnsimport android.view.WindowManager; 288262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 298262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns/** 308262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * Helper for menus that appear as Dialogs (context and submenus). 318262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * 328262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * @hide 338262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns */ 348262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johnspublic class MenuDialogHelper implements DialogInterface.OnKeyListener, 358262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns DialogInterface.OnClickListener, 368262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns DialogInterface.OnDismissListener, 378262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns MenuPresenter.Callback { 388262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns private MenuBuilder mMenu; 398262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns private AlertDialog mDialog; 408262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns ListMenuPresenter mPresenter; 418262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns private MenuPresenter.Callback mPresenterCallback; 428262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 438262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns public MenuDialogHelper(MenuBuilder menu) { 448262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mMenu = menu; 458262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 468262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 478262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns /** 488262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * Shows menu as a dialog. 498262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * 508262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * @param windowToken Optional token to assign to the window. 518262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns */ 528262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns public void show(IBinder windowToken) { 538262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns // Many references to mMenu, create local reference 548262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns final MenuBuilder menu = mMenu; 558262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 568262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns // Get the builder for the dialog 578262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns final AlertDialog.Builder builder = new AlertDialog.Builder(menu.getContext()); 588262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 59176a17e30644b1d5a4206cc462268d151e43949bChris Banes // Need to force Light Menu theme as list_menu_item_layout is usually against a dark bg and 60176a17e30644b1d5a4206cc462268d151e43949bChris Banes // AlertDialog's bg is white 61ee7c9fb199e9b9af8d40a1f9e27d85465acf8301Chris Banes mPresenter = new ListMenuPresenter(R.layout.abc_list_menu_item_layout, 62a2b9cdba583eed47107c1c97bd555c9a181860c2Chris Banes R.style.Theme_AppCompat_CompactMenu_Dialog); 638262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 648262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mPresenter.setCallback(this); 658262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mMenu.addMenuPresenter(mPresenter); 668262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns builder.setAdapter(mPresenter.getAdapter(), this); 678262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 688262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns // Set the title 698262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns final View headerView = menu.getHeaderView(); 708262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (headerView != null) { 718262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns // Menu's client has given a custom header view, use it 728262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns builder.setCustomTitle(headerView); 738262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } else { 748262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns // Otherwise use the (text) title and icon 758262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns builder.setIcon(menu.getHeaderIcon()).setTitle(menu.getHeaderTitle()); 768262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 778262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 788262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns // Set the key listener 798262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns builder.setOnKeyListener(this); 808262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 818262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns // Show the menu 828262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mDialog = builder.create(); 838262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mDialog.setOnDismissListener(this); 848262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 858262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns WindowManager.LayoutParams lp = mDialog.getWindow().getAttributes(); 868262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 878262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (windowToken != null) { 888262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns lp.token = windowToken; 898262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 908262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 918262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 928262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mDialog.show(); 938262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 948262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 958262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { 968262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_BACK) { 978262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (event.getAction() == KeyEvent.ACTION_DOWN 988262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns && event.getRepeatCount() == 0) { 998262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns Window win = mDialog.getWindow(); 1008262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (win != null) { 1018262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns View decor = win.getDecorView(); 1028262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (decor != null) { 1038262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns KeyEvent.DispatcherState ds = decor.getKeyDispatcherState(); 1048262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (ds != null) { 1058262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns ds.startTracking(event, this); 1068262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns return true; 1078262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1088262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1098262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1108262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled()) { 1118262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns Window win = mDialog.getWindow(); 1128262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (win != null) { 1138262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns View decor = win.getDecorView(); 1148262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (decor != null) { 1158262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns KeyEvent.DispatcherState ds = decor.getKeyDispatcherState(); 1168262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (ds != null && ds.isTracking(event)) { 1178262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mMenu.close(true); 1188262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns dialog.dismiss(); 1198262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns return true; 1208262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1218262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1228262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1238262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1248262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1258262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 1268262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns // Menu shortcut matching 1278262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns return mMenu.performShortcut(keyCode, event, 0); 1288262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 1298262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1308262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 1318262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns public void setPresenterCallback(MenuPresenter.Callback cb) { 1328262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mPresenterCallback = cb; 1338262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1348262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 1358262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns /** 1368262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * Dismisses the menu's dialog. 1378262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * 1388262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns * @see Dialog#dismiss() 1398262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns */ 1408262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns public void dismiss() { 1418262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (mDialog != null) { 1428262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mDialog.dismiss(); 1438262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1448262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1458262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 1468262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns @Override 1478262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns public void onDismiss(DialogInterface dialog) { 1488262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mPresenter.onCloseMenu(mMenu, true); 1498262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1508262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 1518262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns @Override 1528262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 1538262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (allMenusAreClosing || menu == mMenu) { 1548262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns dismiss(); 1558262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1568262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (mPresenterCallback != null) { 1578262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mPresenterCallback.onCloseMenu(menu, allMenusAreClosing); 1588262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1598262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1608262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 1618262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns @Override 1628262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns public boolean onOpenSubMenu(MenuBuilder subMenu) { 1638262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns if (mPresenterCallback != null) { 1648262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns return mPresenterCallback.onOpenSubMenu(subMenu); 1658262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1668262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns return false; 1678262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1688262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns 1698262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns public void onClick(DialogInterface dialog, int which) { 1708262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns mMenu.performItemAction((MenuItemImpl) mPresenter.getAdapter().getItem(which), 0); 1718262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns } 1728262949c1a6b7e191020b31fc914972bb0b58ab0Trevor Johns} 173