AppMenuButtonHelper.java revision f2477e01787aa58f445919b809d89e252beef54f
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 5package org.chromium.chrome.browser.appmenu; 6 7import android.view.GestureDetector; 8import android.view.GestureDetector.SimpleOnGestureListener; 9import android.view.MotionEvent; 10import android.view.View; 11import android.view.View.OnTouchListener; 12 13import org.chromium.chrome.browser.UmaBridge; 14 15/** 16 * A helper class for a menu button to decide when to show the app menu and forward touch 17 * events. 18 * 19 * Simply construct this class and pass the class instance to a menu button as TouchListener. 20 * Then this class will handle everything regarding showing app menu for you. 21 */ 22public class AppMenuButtonHelper extends SimpleOnGestureListener implements OnTouchListener { 23 private final View mMenuButton; 24 private final AppMenuHandler mMenuHandler; 25 private final GestureDetector mAppMenuGestureDetector; 26 private boolean mSeenFirstScrollEvent; 27 private Runnable mOnAppMenuShownListener; 28 29 /** 30 * @param menuButton Menu button instance that will trigger the app menu. 31 * @param menuHandler MenuHandler implementation that can show and get the app menu. 32 */ 33 public AppMenuButtonHelper(View menuButton, AppMenuHandler menuHandler) { 34 mMenuButton = menuButton; 35 mMenuHandler = menuHandler; 36 mAppMenuGestureDetector = new GestureDetector(menuButton.getContext(), this); 37 mAppMenuGestureDetector.setIsLongpressEnabled(false); 38 } 39 40 /** 41 * @param onAppMenuShownListener This is called when the app menu is shown by this class. 42 */ 43 public void setOnAppMenuShownListener(Runnable onAppMenuShownListener) { 44 mOnAppMenuShownListener = onAppMenuShownListener; 45 } 46 47 /** 48 * Shows the app menu if it is not already shown. 49 * @param startDragging Whether dragging is started. 50 * @return Whether or not if the app menu is successfully shown. 51 */ 52 private boolean showAppMenu(boolean startDragging) { 53 if (!mMenuHandler.isAppMenuShowing() && 54 mMenuHandler.showAppMenu(mMenuButton, false, startDragging)) { 55 UmaBridge.usingMenu(false, startDragging); 56 if (mOnAppMenuShownListener != null) { 57 mOnAppMenuShownListener.run(); 58 } 59 return true; 60 } 61 return false; 62 } 63 64 /** 65 * @return Whether the App Menu is currently showing. 66 */ 67 public boolean isAppMenuShowing() { 68 return mMenuHandler.isAppMenuShowing(); 69 } 70 71 /** 72 * Handle the key press event on a menu button. 73 * @return Whether the app menu was shown as a result of this action. 74 */ 75 public boolean onEnterKeyPress() { 76 return showAppMenu(false); 77 } 78 79 @Override 80 public boolean onDown(MotionEvent e) { 81 mSeenFirstScrollEvent = false; 82 mMenuButton.setPressed(true); 83 84 return true; 85 } 86 87 @Override 88 public boolean onSingleTapUp(MotionEvent e) { 89 // A single tap shows the app menu, but dragging disabled. 90 return showAppMenu(false); 91 } 92 93 @Override 94 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 95 if (mSeenFirstScrollEvent) return false; 96 mSeenFirstScrollEvent = true; 97 98 // If the scrolling direction is roughly down on the first onScroll detection, 99 // we consider it as dragging start, so shows the app menu. Otherwise, we 100 // don't show menu so that toolbar horizontal swiping can happen. 101 return -distanceY >= Math.abs(distanceX) && showAppMenu(true); 102 } 103 104 @Override 105 public boolean onTouch(View view, MotionEvent event) { 106 if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || 107 event.getActionMasked() == MotionEvent.ACTION_UP) { 108 mMenuButton.setPressed(false); 109 } 110 111 // This will take care of showing app menu. 112 boolean isTouchEventConsumed = mAppMenuGestureDetector.onTouchEvent(event); 113 114 // If user starts to drag on this menu button, ACTION_DOWN and all the subsequent touch 115 // events are received here. We need to forward this event to the app menu to handle 116 // dragging correctly. 117 AppMenu menu = mMenuHandler.getAppMenu(); 118 if (menu != null && !isTouchEventConsumed) { 119 isTouchEventConsumed |= menu.handleDragging(event); 120 } 121 return isTouchEventConsumed; 122 } 123}