1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)package org.chromium.chrome.browser.appmenu; 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.app.Activity; 823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.content.res.TypedArray; 923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.graphics.Rect; 100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.graphics.drawable.Drawable; 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.ContextThemeWrapper; 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.Menu; 1323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.view.MenuItem; 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.View; 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.widget.PopupMenu; 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import com.google.common.annotations.VisibleForTesting; 1823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.chromium.chrome.browser.UmaBridge; 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import java.util.ArrayList; 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)/** 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Object responsible for handling the creation, showing, hiding of the AppMenu and notifying the 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * AppMenuObservers about these actions. 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)public class AppMenuHandler { 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private AppMenu mAppMenu; 2923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private AppMenuDragHelper mAppMenuDragHelper; 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private Menu mMenu; 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private final ArrayList<AppMenuObserver> mObservers; 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private final int mMenuResourceId; 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private final AppMenuPropertiesDelegate mDelegate; 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private final Activity mActivity; 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Constructs an AppMenuHandler object. 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param activity Activity that is using the AppMenu. 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param delegate Delegate used to check the desired AppMenu properties on show. 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param menuResourceId Resource Id that should be used as the source for the menu items. 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * It is assumed to have back_menu_id, forward_menu_id, bookmark_this_page_id. 43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public AppMenuHandler(Activity activity, AppMenuPropertiesDelegate delegate, 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int menuResourceId) { 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mActivity = activity; 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mDelegate = delegate; 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mObservers = new ArrayList<AppMenuObserver>(); 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mMenuResourceId = menuResourceId; 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Show the app menu. 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param anchorView Anchor view (usually a menu button) to be used for the popup. 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param isByHardwareButton True if hardware button triggered it. (oppose to software 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * button) 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param startDragging Whether dragging is started. For example, if the app menu is 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * showed by tapping on a button, this should be false. If it is 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * showed by start dragging down on the menu button, this should 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * be true. Note that if isByHardwareButton is true, this must 61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * be false since we no longer support hardware menu button 62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * dragging. 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @return True, if the menu is shown, false, if menu is not shown, example reasons: 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * the menu is not yet available to be shown, or the menu is already showing. 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public boolean showAppMenu(View anchorView, boolean isByHardwareButton, boolean startDragging) { 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) assert !(isByHardwareButton && startDragging); 68c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!mDelegate.shouldShowAppMenu() || isAppMenuShowing()) return false; 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mMenu == null) { 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Use a PopupMenu to create the Menu object. Note this is not the same as the 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // AppMenu (mAppMenu) created below. 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) PopupMenu tempMenu = new PopupMenu(mActivity, anchorView); 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) tempMenu.inflate(mMenuResourceId); 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mMenu = tempMenu.getMenu(); 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mDelegate.prepareMenu(mMenu); 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 79bee9932bab44713b74b422b4b759b49f5a222977Bo Liu ContextThemeWrapper wrapper = new ContextThemeWrapper(mActivity, 80bee9932bab44713b74b422b4b759b49f5a222977Bo Liu mDelegate.getMenuThemeResourceId()); 81bee9932bab44713b74b422b4b759b49f5a222977Bo Liu 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mAppMenu == null) { 83bee9932bab44713b74b422b4b759b49f5a222977Bo Liu TypedArray a = wrapper.obtainStyledAttributes(new int[] 840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch {android.R.attr.listPreferredItemHeightSmall, android.R.attr.listDivider}); 8523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int itemRowHeight = a.getDimensionPixelSize(0, 0); 860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Drawable itemDivider = a.getDrawable(1); 87bee9932bab44713b74b422b4b759b49f5a222977Bo Liu int itemDividerHeight = itemDivider != null ? itemDivider.getIntrinsicHeight() : 0; 8823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) a.recycle(); 890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch mAppMenu = new AppMenu(mMenu, itemRowHeight, itemDividerHeight, this, 900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch mActivity.getResources()); 9123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mAppMenuDragHelper = new AppMenuDragHelper(mActivity, mAppMenu, itemRowHeight); 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 9423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // Get the height and width of the display. 9523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) Rect appRect = new Rect(); 9623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(appRect); 9723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation(); 9823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mAppMenu.show(wrapper, anchorView, isByHardwareButton, rotation, appRect); 99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) mAppMenuDragHelper.onShow(startDragging); 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) UmaBridge.menuShow(); 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 10423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) void appMenuDismissed() { 10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mAppMenuDragHelper.onDismiss(); 10623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 10723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @return Whether the App Menu is currently showing. 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public boolean isAppMenuShowing() { 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return mAppMenu != null && mAppMenu.isShowing(); 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @return The App Menu that the menu handler is interacting with. 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 11823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) @VisibleForTesting 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AppMenu getAppMenu() { 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return mAppMenu; 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 12323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) AppMenuDragHelper getAppMenuDragHelper() { 12423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return mAppMenuDragHelper; 12523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 12623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Requests to hide the App Menu. 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public void hideAppMenu() { 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mAppMenu != null && mAppMenu.isShowing()) mAppMenu.dismiss(); 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Adds the observer to App Menu. 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param observer Observer that should be notified about App Menu changes. 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public void addObserver(AppMenuObserver observer) { 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mObservers.add(observer); 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Removes the observer from the App Menu. 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param observer Observer that should no longer be notified about App Menu changes. 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public void removeObserver(AppMenuObserver observer) { 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mObservers.remove(observer); 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 15023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) void onOptionsItemSelected(MenuItem item) { 15123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mActivity.onOptionsItemSelected(item); 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 15523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * Called by AppMenu to report that the App Menu visibility has changed. 15623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * @param isVisible Whether the App Menu is showing. 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 15823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) void onMenuVisibilityChanged(boolean isVisible) { 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (int i = 0; i < mObservers.size(); ++i) { 16023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mObservers.get(i).onMenuVisibilityChanged(isVisible); 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 164