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; 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import android.graphics.Point; 1023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.graphics.Rect; 110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.graphics.drawable.Drawable; 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.ContextThemeWrapper; 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.Menu; 1423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)import android.view.MenuItem; 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.view.View; 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import android.widget.PopupMenu; 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport org.chromium.base.VisibleForTesting; 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) 79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ContextThemeWrapper wrapper = new ContextThemeWrapper(mActivity, 80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch mDelegate.getMenuThemeResourceId()); 81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mAppMenu == null) { 83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 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); 87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 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); 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Use full size of window for abnormal appRect. 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (appRect.left < 0 && appRect.top < 0) { 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) appRect.left = 0; 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) appRect.top = 0; 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) appRect.right = mActivity.getWindow().getDecorView().getWidth(); 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) appRect.bottom = mActivity.getWindow().getDecorView().getHeight(); 1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 10523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation(); 1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Point pt = new Point(); 1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mActivity.getWindowManager().getDefaultDisplay().getSize(pt); 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mAppMenu.show(wrapper, anchorView, isByHardwareButton, rotation, appRect, pt.y); 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) mAppMenuDragHelper.onShow(startDragging); 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) UmaBridge.menuShow(); 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 11423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) void appMenuDismissed() { 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) mAppMenuDragHelper.finishDragging(); 11623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 11723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @return Whether the App Menu is currently showing. 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public boolean isAppMenuShowing() { 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return mAppMenu != null && mAppMenu.isShowing(); 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @return The App Menu that the menu handler is interacting with. 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 12823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) @VisibleForTesting 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) AppMenu getAppMenu() { 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return mAppMenu; 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 13323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) AppMenuDragHelper getAppMenuDragHelper() { 13423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return mAppMenuDragHelper; 13523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 13623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Requests to hide the App Menu. 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public void hideAppMenu() { 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (mAppMenu != null && mAppMenu.isShowing()) mAppMenu.dismiss(); 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Adds the observer to App Menu. 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param observer Observer that should be notified about App Menu changes. 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public void addObserver(AppMenuObserver observer) { 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mObservers.add(observer); 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * Removes the observer from the App Menu. 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) * @param observer Observer that should no longer be notified about App Menu changes. 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public void removeObserver(AppMenuObserver observer) { 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mObservers.remove(observer); 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 16023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) void onOptionsItemSelected(MenuItem item) { 16123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mActivity.onOptionsItemSelected(item); 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) /** 16523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * Called by AppMenu to report that the App Menu visibility has changed. 16623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * @param isVisible Whether the App Menu is showing. 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) */ 16823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) void onMenuVisibilityChanged(boolean isVisible) { 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (int i = 0; i < mObservers.size(); ++i) { 17023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mObservers.get(i).onMenuVisibilityChanged(isVisible); 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 174