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