• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 package org.chromium.chrome.browser.appmenu;
6 
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;
16 
17 import com.google.common.annotations.VisibleForTesting;
18 
19 import org.chromium.chrome.browser.UmaBridge;
20 
21 import java.util.ArrayList;
22 
23 /**
24  * Object responsible for handling the creation, showing, hiding of the AppMenu and notifying the
25  * AppMenuObservers about these actions.
26  */
27 public class AppMenuHandler {
28     private AppMenu mAppMenu;
29     private AppMenuDragHelper mAppMenuDragHelper;
30     private Menu mMenu;
31     private final ArrayList<AppMenuObserver> mObservers;
32     private final int mMenuResourceId;
33 
34     private final AppMenuPropertiesDelegate mDelegate;
35     private final Activity mActivity;
36 
37     /**
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.
43      */
AppMenuHandler(Activity activity, AppMenuPropertiesDelegate delegate, int menuResourceId)44     public AppMenuHandler(Activity activity, AppMenuPropertiesDelegate delegate,
45             int menuResourceId) {
46         mActivity = activity;
47         mDelegate = delegate;
48         mObservers = new ArrayList<AppMenuObserver>();
49         mMenuResourceId = menuResourceId;
50     }
51 
52     /**
53      * Show the app menu.
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
56      *                           button)
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 must
61      *                           be false since we no longer support hardware menu button
62      *                           dragging.
63      * @return True, if the menu is shown, false, if menu is not shown, example reasons:
64      *         the menu is not yet available to be shown, or the menu is already showing.
65      */
showAppMenu(View anchorView, boolean isByHardwareButton, boolean startDragging)66     public boolean showAppMenu(View anchorView, boolean isByHardwareButton, boolean startDragging) {
67         assert !(isByHardwareButton && startDragging);
68         if (!mDelegate.shouldShowAppMenu() || isAppMenuShowing()) return false;
69 
70         if (mMenu == null) {
71             // Use a PopupMenu to create the Menu object. Note this is not the same as the
72             // AppMenu (mAppMenu) created below.
73             PopupMenu tempMenu = new PopupMenu(mActivity, anchorView);
74             tempMenu.inflate(mMenuResourceId);
75             mMenu = tempMenu.getMenu();
76         }
77         mDelegate.prepareMenu(mMenu);
78 
79         ContextThemeWrapper wrapper = new ContextThemeWrapper(mActivity,
80                 mDelegate.getMenuThemeResourceId());
81 
82         if (mAppMenu == null) {
83             TypedArray a = wrapper.obtainStyledAttributes(new int[]
84                     {android.R.attr.listPreferredItemHeightSmall, android.R.attr.listDivider});
85             int itemRowHeight = a.getDimensionPixelSize(0, 0);
86             Drawable itemDivider = a.getDrawable(1);
87             int itemDividerHeight = itemDivider != null ? itemDivider.getIntrinsicHeight() : 0;
88             a.recycle();
89             mAppMenu = new AppMenu(mMenu, itemRowHeight, itemDividerHeight, this,
90                     mActivity.getResources());
91             mAppMenuDragHelper = new AppMenuDragHelper(mActivity, mAppMenu, itemRowHeight);
92         }
93 
94         // Get the height and width of the display.
95         Rect appRect = new Rect();
96         mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(appRect);
97         int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
98         mAppMenu.show(wrapper, anchorView, isByHardwareButton, rotation, appRect);
99         mAppMenuDragHelper.onShow(startDragging);
100         UmaBridge.menuShow();
101         return true;
102     }
103 
appMenuDismissed()104     void appMenuDismissed() {
105         mAppMenuDragHelper.onDismiss();
106     }
107 
108     /**
109      * @return Whether the App Menu is currently showing.
110      */
isAppMenuShowing()111     public boolean isAppMenuShowing() {
112         return mAppMenu != null && mAppMenu.isShowing();
113     }
114 
115     /**
116      * @return The App Menu that the menu handler is interacting with.
117      */
118     @VisibleForTesting
getAppMenu()119     AppMenu getAppMenu() {
120         return mAppMenu;
121     }
122 
getAppMenuDragHelper()123     AppMenuDragHelper getAppMenuDragHelper() {
124         return mAppMenuDragHelper;
125     }
126 
127     /**
128      * Requests to hide the App Menu.
129      */
hideAppMenu()130     public void hideAppMenu() {
131         if (mAppMenu != null && mAppMenu.isShowing()) mAppMenu.dismiss();
132     }
133 
134     /**
135      * Adds the observer to App Menu.
136      * @param observer Observer that should be notified about App Menu changes.
137      */
addObserver(AppMenuObserver observer)138     public void addObserver(AppMenuObserver observer) {
139         mObservers.add(observer);
140     }
141 
142     /**
143      * Removes the observer from the App Menu.
144      * @param observer Observer that should no longer be notified about App Menu changes.
145      */
removeObserver(AppMenuObserver observer)146     public void removeObserver(AppMenuObserver observer) {
147         mObservers.remove(observer);
148     }
149 
onOptionsItemSelected(MenuItem item)150     void onOptionsItemSelected(MenuItem item) {
151         mActivity.onOptionsItemSelected(item);
152     }
153 
154     /**
155      * Called by AppMenu to report that the App Menu visibility has changed.
156      * @param isVisible Whether the App Menu is showing.
157      */
onMenuVisibilityChanged(boolean isVisible)158     void onMenuVisibilityChanged(boolean isVisible) {
159         for (int i = 0; i < mObservers.size(); ++i) {
160             mObservers.get(i).onMenuVisibilityChanged(isVisible);
161         }
162     }
163 }
164