1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.chrome.browser.appmenu;
7 import android.app.Activity;
8 import android.content.res.TypedArray;
9 import android.graphics.Rect;
10 import android.graphics.drawable.Drawable;
11 import android.view.ContextThemeWrapper;
12 import android.view.Menu;
13 import android.view.MenuItem;
14 import android.view.View;
15 import android.widget.PopupMenu;
17 import com.google.common.annotations.VisibleForTesting;
19 import org.chromium.chrome.browser.UmaBridge;
21 import java.util.ArrayList;
24 * Object responsible for handling the creation, showing, hiding of the AppMenu and notifying the
25 * AppMenuObservers about these actions.
27 public class AppMenuHandler {
28 private AppMenu mAppMenu;
29 private AppMenuDragHelper mAppMenuDragHelper;
31 private final ArrayList<AppMenuObserver> mObservers;
32 private final int mMenuResourceId;
34 private final AppMenuPropertiesDelegate mDelegate;
35 private final Activity mActivity;
38 * Constructs an AppMenuHandler object.
39 * @param activity Activity that is using the AppMenu.
40 * @param delegate Delegate used to check the desired AppMenu properties on show.
41 * @param menuResourceId Resource Id that should be used as the source for the menu items.
42 * It is assumed to have back_menu_id, forward_menu_id, bookmark_this_page_id.
44 public AppMenuHandler(Activity activity, AppMenuPropertiesDelegate delegate,
48 mObservers = new ArrayList<AppMenuObserver>();
49 mMenuResourceId = menuResourceId;
54 * @param anchorView Anchor view (usually a menu button) to be used for the popup.
55 * @param isByHardwareButton True if hardware button triggered it. (oppose to software
57 * @param startDragging Whether dragging is started. For example, if the app menu is
58 * showed by tapping on a button, this should be false. If it is
59 * showed by start dragging down on the menu button, this should
60 * be true. Note that if isByHardwareButton is true, this is
62 * @return True, if the menu is shown, false, if menu is not shown, example reasons:
63 * the menu is not yet available to be shown, or the menu is already showing.
65 public boolean showAppMenu(View anchorView, boolean isByHardwareButton, boolean startDragging) {
66 if (!mDelegate.shouldShowAppMenu() || isAppMenuShowing()) return false;
69 // Use a PopupMenu to create the Menu object. Note this is not the same as the
70 // AppMenu (mAppMenu) created below.
71 PopupMenu tempMenu = new PopupMenu(mActivity, anchorView);
72 tempMenu.inflate(mMenuResourceId);
73 mMenu = tempMenu.getMenu();
75 mDelegate.prepareMenu(mMenu);
77 if (mAppMenu == null) {
78 TypedArray a = mActivity.obtainStyledAttributes(new int[]
79 {android.R.attr.listPreferredItemHeightSmall, android.R.attr.listDivider});
80 int itemRowHeight = a.getDimensionPixelSize(0, 0);
81 Drawable itemDivider = a.getDrawable(1);
82 int itemDividerHeight = itemDivider.getIntrinsicHeight();
84 mAppMenu = new AppMenu(mMenu, itemRowHeight, itemDividerHeight, this,
85 mActivity.getResources());
86 mAppMenuDragHelper = new AppMenuDragHelper(mActivity, mAppMenu, itemRowHeight);
89 ContextThemeWrapper wrapper = new ContextThemeWrapper(mActivity,
90 mDelegate.getMenuThemeResourceId());
91 // Get the height and width of the display.
92 Rect appRect = new Rect();
93 mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(appRect);
94 int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
95 mAppMenu.show(wrapper, anchorView, isByHardwareButton, rotation, appRect);
96 mAppMenuDragHelper.onShow(isByHardwareButton, startDragging);
101 void appMenuDismissed() {
102 mAppMenuDragHelper.onDismiss();
106 * @return Whether the App Menu is currently showing.
108 public boolean isAppMenuShowing() {
109 return mAppMenu != null && mAppMenu.isShowing();
113 * @return The App Menu that the menu handler is interacting with.
116 AppMenu getAppMenu() {
120 AppMenuDragHelper getAppMenuDragHelper() {
121 return mAppMenuDragHelper;
125 * Requests to hide the App Menu.
127 public void hideAppMenu() {
128 if (mAppMenu != null && mAppMenu.isShowing()) mAppMenu.dismiss();
132 * Adds the observer to App Menu.
133 * @param observer Observer that should be notified about App Menu changes.
135 public void addObserver(AppMenuObserver observer) {
136 mObservers.add(observer);
140 * Removes the observer from the App Menu.
141 * @param observer Observer that should no longer be notified about App Menu changes.
143 public void removeObserver(AppMenuObserver observer) {
144 mObservers.remove(observer);
147 void onOptionsItemSelected(MenuItem item) {
148 mActivity.onOptionsItemSelected(item);
152 * Called by AppMenu to report that the App Menu visibility has changed.
153 * @param isVisible Whether the App Menu is showing.
155 void onMenuVisibilityChanged(boolean isVisible) {
156 for (int i = 0; i < mObservers.size(); ++i) {
157 mObservers.get(i).onMenuVisibilityChanged(isVisible);
162 * TODO(kkimlabs) remove this call.
164 public void hardwareMenuButtonUp() {
165 if (mAppMenuDragHelper != null) mAppMenuDragHelper.hardwareMenuButtonUp();