MenuPopupHelper.java revision 6142a54baae3289f734947c6b5375b12eb0fb722
1bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/* 2bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Copyright (C) 2010 The Android Open Source Project 3bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * 4bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 5bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * you may not use this file except in compliance with the License. 6bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * You may obtain a copy of the License at 7bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * 8bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * http://www.apache.org/licenses/LICENSE-2.0 9bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * 10bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Unless required by applicable law or agreed to in writing, software 11bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * distributed under the License is distributed on an "AS IS" BASIS, 12bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * See the License for the specific language governing permissions and 14bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * limitations under the License. 15bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 16bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 1766698bb15ba0f873aa1c2290cc50d6bb839a474aChris Banespackage android.support.v7.view.menu; 18bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 19bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.content.Context; 206142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.graphics.Rect; 216142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.support.annotation.AttrRes; 226142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.support.annotation.NonNull; 236142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.support.annotation.Nullable; 246142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.support.annotation.StyleRes; 256142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.support.v4.view.GravityCompat; 266142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.support.v4.view.ViewCompat; 27da10fdd1400ecfd8d7f2e55651dd528d0614dfc5Jeff Brownimport android.support.v7.appcompat.R; 2849c78900da0d43140fb602431fb93212bd7f6c70Chris Banesimport android.view.Gravity; 29bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powellimport android.view.View; 306142a54baae3289f734947c6b5375b12eb0fb722Chris Banesimport android.widget.PopupWindow.OnDismissListener; 31bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 32bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell/** 33bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * Presents a menu as a small, simple popup anchored to another view. 34ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani * 35bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell * @hide 36bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell */ 376142a54baae3289f734947c6b5375b12eb0fb722Chris Banespublic class MenuPopupHelper implements MenuHelper { 386142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private static final int TOUCH_EPICENTER_SIZE_DP = 48; 39bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 4049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private final Context mContext; 416142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 426142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // Immutable cached popup menu properties. 4349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private final MenuBuilder mMenu; 4449c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private final boolean mOverflowOnly; 4549c78900da0d43140fb602431fb93212bd7f6c70Chris Banes private final int mPopupStyleAttr; 46a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette private final int mPopupStyleRes; 4749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 486142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // Mutable cached popup menu properties. 49ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani private View mAnchorView; 506142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private int mDropDownGravity = Gravity.START; 516142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private boolean mForceShowIcon; 526142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private MenuPresenter.Callback mPresenterCallback; 5349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 546142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private MenuPopup mPopup; 556142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private OnDismissListener mOnDismissListener; 5649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 576142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public MenuPopupHelper(@NonNull Context context, @NonNull MenuBuilder menu) { 586142a54baae3289f734947c6b5375b12eb0fb722Chris Banes this(context, menu, null, false, R.attr.popupMenuStyle, 0); 59ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 60bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 616142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public MenuPopupHelper(@NonNull Context context, @NonNull MenuBuilder menu, 626142a54baae3289f734947c6b5375b12eb0fb722Chris Banes @NonNull View anchorView) { 636142a54baae3289f734947c6b5375b12eb0fb722Chris Banes this(context, menu, anchorView, false, R.attr.popupMenuStyle, 0); 64ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 65bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 666142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public MenuPopupHelper(@NonNull Context context, @NonNull MenuBuilder menu, 676142a54baae3289f734947c6b5375b12eb0fb722Chris Banes @NonNull View anchorView, 686142a54baae3289f734947c6b5375b12eb0fb722Chris Banes boolean overflowOnly, @AttrRes int popupStyleAttr) { 69a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette this(context, menu, anchorView, overflowOnly, popupStyleAttr, 0); 70a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette } 71a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette 726142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public MenuPopupHelper(@NonNull Context context, @NonNull MenuBuilder menu, 736142a54baae3289f734947c6b5375b12eb0fb722Chris Banes @NonNull View anchorView, boolean overflowOnly, @AttrRes int popupStyleAttr, 746142a54baae3289f734947c6b5375b12eb0fb722Chris Banes @StyleRes int popupStyleRes) { 75ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mContext = context; 76ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mMenu = menu; 776142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mAnchorView = anchorView; 78ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mOverflowOnly = overflowOnly; 7949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mPopupStyleAttr = popupStyleAttr; 80a9cf27da7f78d81db5ad482003a10d1a6562107cAlan Viverette mPopupStyleRes = popupStyleRes; 816142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 82bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 836142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void setOnDismissListener(@Nullable OnDismissListener listener) { 846142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mOnDismissListener = listener; 85ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 86bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 876142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 886142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Sets the view to which the popup window is anchored. 896142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * <p> 906142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Changes take effect on the next call to show(). 916142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 926142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @param anchor the view to which the popup window should be anchored 936142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 946142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void setAnchorView(@NonNull View anchor) { 95ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani mAnchorView = anchor; 96ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 97bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 986142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 996142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Sets whether the popup menu's adapter is forced to show icons in the 1006142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * menu item views. 1016142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * <p> 1026142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Changes take effect on the next call to show(). 1036142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 1046142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @param forceShowIcon {@code true} to force icons to be shown, or 1056142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * {@code false} for icons to be optionally shown 1066142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 1076142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void setForceShowIcon(boolean forceShowIcon) { 1086142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mForceShowIcon = forceShowIcon; 109bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 110ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 1116142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 1126142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Sets the alignment of the popup window relative to the anchor view. 1136142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * <p> 1146142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Changes take effect on the next call to show(). 1156142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 1166142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @param gravity alignment of the popup relative to the anchor 1176142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 11849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes public void setGravity(int gravity) { 11949c78900da0d43140fb602431fb93212bd7f6c70Chris Banes mDropDownGravity = gravity; 12049c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 12149c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 1226142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 1236142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @return alignment of the popup relative to the anchor 1246142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 12544918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes public int getGravity() { 12644918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes return mDropDownGravity; 12744918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes } 12844918a92e1d66a01a03063e2c5e68b2570f64b03Chris Banes 129ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public void show() { 130ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (!tryShow()) { 131ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); 132ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 133bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 134bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 1356142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void show(int x, int y) { 1366142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (!tryShow(x, y)) { 1376142a54baae3289f734947c6b5375b12eb0fb722Chris Banes throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); 1386142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1396142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 1406142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 1416142a54baae3289f734947c6b5375b12eb0fb722Chris Banes @NonNull 1426142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public MenuPopup getPopup() { 1436142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (mPopup == null) { 1446142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mPopup = createPopup(); 1456142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 14649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes return mPopup; 14749c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 14849c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 1496142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 1506142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Attempts to show the popup anchored to the view specified by {@link #setAnchorView(View)}. 1516142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 1526142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @return {@code true} if the popup was shown or was already showing prior to calling this 1536142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * method, {@code false} otherwise 1546142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 155ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani public boolean tryShow() { 1566142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (isShowing()) { 1576142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return true; 158ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 159bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 1606142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (mAnchorView == null) { 1616142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return false; 16249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes } 16349c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 1646142a54baae3289f734947c6b5375b12eb0fb722Chris Banes showPopup(0, 0, false, false); 165ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani return true; 166bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 167ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 1686142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 1696142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Shows the popup menu and makes a best-effort to anchor it to the 1706142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * specified (x,y) coordinate relative to the anchor view. 1716142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * <p> 1726142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Additionally, the popup's transition epicenter (see 1736142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * {@link android.widget.PopupWindow#setEpicenterBounds(Rect)} will be 1746142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * centered on the specified coordinate, rather than using the bounds of 1756142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * the anchor view. 1766142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * <p> 1776142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * If the popup's resolved gravity is {@link Gravity#LEFT}, this will 1786142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * display the popup with its top-left corner at (x,y) relative to the 1796142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * anchor view. If the resolved gravity is {@link Gravity#RIGHT}, the 1806142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * popup's top-right corner will be at (x,y). 1816142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * <p> 1826142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * If the popup cannot be displayed fully on-screen, this method will 1836142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * attempt to scroll the anchor view's ancestors and/or offset the popup 1846142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * such that it may be displayed fully on-screen. 1856142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 1866142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @param x x coordinate relative to the anchor view 1876142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @param y y coordinate relative to the anchor view 1886142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @return {@code true} if the popup was shown or was already showing prior 1896142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * to calling this method, {@code false} otherwise 1906142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 1916142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public boolean tryShow(int x, int y) { 192ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani if (isShowing()) { 1936142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return true; 194ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 195ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 1966142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (mAnchorView == null) { 1976142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return false; 198ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 199ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 2006142a54baae3289f734947c6b5375b12eb0fb722Chris Banes showPopup(x, y, true, true); 2016142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return true; 202ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 203bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 2046142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 2056142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Creates the popup and assigns cached properties. 2066142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * 2076142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * @return an initialized popup 2086142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 2096142a54baae3289f734947c6b5375b12eb0fb722Chris Banes @NonNull 2106142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private MenuPopup createPopup() { 2116142a54baae3289f734947c6b5375b12eb0fb722Chris Banes final boolean enableCascadingSubmenus = mContext.getResources().getBoolean( 2126142a54baae3289f734947c6b5375b12eb0fb722Chris Banes R.bool.abc_config_enableCascadingSubmenus); 2136142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 2146142a54baae3289f734947c6b5375b12eb0fb722Chris Banes final MenuPopup popup; 2156142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (enableCascadingSubmenus) { 2166142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup = new CascadingMenuPopup(mContext, mAnchorView, mPopupStyleAttr, 2176142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mPopupStyleRes, mOverflowOnly); 2186142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } else { 2196142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup = new StandardMenuPopup(mContext, mMenu, mAnchorView, mPopupStyleAttr, 2206142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mPopupStyleRes, mOverflowOnly); 221ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 222ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 2236142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // Assign immutable properties. 2246142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.addMenu(mMenu); 2256142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.setOnDismissListener(mInternalOnDismissListener); 22649c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 2276142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // Assign mutable properties. These may be reassigned later. 2286142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.setAnchorView(mAnchorView); 2296142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.setCallback(mPresenterCallback); 2306142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.setForceShowIcon(mForceShowIcon); 2316142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.setGravity(mDropDownGravity); 23249c78900da0d43140fb602431fb93212bd7f6c70Chris Banes 2336142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return popup; 234ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 235bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 2366142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private void showPopup(int xOffset, int yOffset, boolean useOffsets, boolean showTitle) { 2376142a54baae3289f734947c6b5375b12eb0fb722Chris Banes final MenuPopup popup = getPopup(); 2386142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.setShowTitle(showTitle); 2396142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 2406142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (useOffsets) { 2416142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // If the resolved drop-down gravity is RIGHT, the popup's right 2426142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // edge will be aligned with the anchor view. Adjust by the anchor 2436142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // width such that the top-right corner is at the X offset. 2446142a54baae3289f734947c6b5375b12eb0fb722Chris Banes final int hgrav = GravityCompat.getAbsoluteGravity(mDropDownGravity, 2456142a54baae3289f734947c6b5375b12eb0fb722Chris Banes ViewCompat.getLayoutDirection(mAnchorView)) & Gravity.HORIZONTAL_GRAVITY_MASK; 2466142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (hgrav == Gravity.RIGHT) { 2476142a54baae3289f734947c6b5375b12eb0fb722Chris Banes xOffset -= mAnchorView.getWidth(); 248ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 249bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 2506142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.setHorizontalOffset(xOffset); 2516142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.setVerticalOffset(yOffset); 2526142a54baae3289f734947c6b5375b12eb0fb722Chris Banes 2536142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // Set the transition epicenter to be roughly finger (or mouse 2546142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // cursor) sized and centered around the offset position. This 2556142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // will give the appearance that the window is emerging from 2566142a54baae3289f734947c6b5375b12eb0fb722Chris Banes // the touch point. 2576142a54baae3289f734947c6b5375b12eb0fb722Chris Banes final float density = mContext.getResources().getDisplayMetrics().density; 2586142a54baae3289f734947c6b5375b12eb0fb722Chris Banes final int halfSize = (int) (TOUCH_EPICENTER_SIZE_DP * density / 2); 2596142a54baae3289f734947c6b5375b12eb0fb722Chris Banes final Rect epicenter = new Rect(xOffset - halfSize, yOffset - halfSize, 2606142a54baae3289f734947c6b5375b12eb0fb722Chris Banes xOffset + halfSize, yOffset + halfSize); 2616142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.setEpicenterBounds(epicenter); 26220ac724a3a836bfd362c911f7dc55a61c02b4d44Trevor Johns } 263bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 2646142a54baae3289f734947c6b5375b12eb0fb722Chris Banes popup.show(); 265bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 266bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 2676142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 2686142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Dismisses the popup, if showing. 2696142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 270ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 2716142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void dismiss() { 2726142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (isShowing()) { 2736142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mPopup.dismiss(); 274ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 275bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 276bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 2776142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 2786142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Called after the popup has been dismissed. 2796142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * <p> 2806142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * <strong>Note:</strong> Subclasses should call the super implementation 2816142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * last to ensure that any necessary tear down has occurred before the 2826142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * listener specified by {@link #setOnDismissListener(OnDismissListener)} 2836142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * is called. 2846142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 2856142a54baae3289f734947c6b5375b12eb0fb722Chris Banes protected void onDismiss() { 2866142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mPopup = null; 287ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 2886142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (mOnDismissListener != null) { 2896142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mOnDismissListener.onDismiss(); 290bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 291bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell } 292bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell 2936142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public boolean isShowing() { 2946142a54baae3289f734947c6b5375b12eb0fb722Chris Banes return mPopup != null && mPopup.isShowing(); 295ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 296ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 297ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 2986142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void setPresenterCallback(@Nullable MenuPresenter.Callback cb) { 2996142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mPresenterCallback = cb; 3006142a54baae3289f734947c6b5375b12eb0fb722Chris Banes if (mPopup != null) { 3016142a54baae3289f734947c6b5375b12eb0fb722Chris Banes mPopup.setCallback(cb); 302ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 3036142a54baae3289f734947c6b5375b12eb0fb722Chris Banes } 304ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani 3056142a54baae3289f734947c6b5375b12eb0fb722Chris Banes /** 3066142a54baae3289f734947c6b5375b12eb0fb722Chris Banes * Listener used to proxy dismiss callbacks to the helper's owner. 3076142a54baae3289f734947c6b5375b12eb0fb722Chris Banes */ 3086142a54baae3289f734947c6b5375b12eb0fb722Chris Banes private final OnDismissListener mInternalOnDismissListener = new OnDismissListener() { 309ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani @Override 3106142a54baae3289f734947c6b5375b12eb0fb722Chris Banes public void onDismiss() { 3116142a54baae3289f734947c6b5375b12eb0fb722Chris Banes MenuPopupHelper.this.onDismiss(); 312ced50ab7536cd3d3573f03310fc899f10c414d37Anirudh Dewani } 3136142a54baae3289f734947c6b5375b12eb0fb722Chris Banes }; 314bbbb8f39d1b1d1b317c5f9237f20fe6b1d9eb17fAdam Powell} 315