10c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki/* 20c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Copyright (C) 2015 The Android Open Source Project 30c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * 40c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Licensed under the Apache License, Version 2.0 (the "License"); 50c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * you may not use this file except in compliance with the License. 60c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * You may obtain a copy of the License at 70c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * 80c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * http://www.apache.org/licenses/LICENSE-2.0 90c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * 100c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Unless required by applicable law or agreed to in writing, software 110c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * distributed under the License is distributed on an "AS IS" BASIS, 120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * See the License for the specific language governing permissions and 140c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * limitations under the License. 150c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 160c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokipackage com.android.internal.widget; 180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.animation.Animator; 200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.animation.AnimatorListenerAdapter; 210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.animation.AnimatorSet; 220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.animation.ObjectAnimator; 237e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Tokiimport android.animation.ValueAnimator; 2429cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Tokiimport android.annotation.Nullable; 250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.content.Context; 26079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Tokiimport android.content.res.TypedArray; 270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.graphics.Color; 280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.graphics.Point; 290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.graphics.Rect; 30517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.graphics.Region; 317e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Tokiimport android.graphics.drawable.AnimatedVectorDrawable; 320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.graphics.drawable.ColorDrawable; 337e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Tokiimport android.graphics.drawable.Drawable; 34b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Tokiimport android.text.TextUtils; 35517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.util.Size; 365fedfb8d469ea5d1911be3ec44c2c19e7946a6e3Abodunrinwa Tokiimport android.util.TypedValue; 37079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Tokiimport android.view.ContextThemeWrapper; 380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Gravity; 390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.LayoutInflater; 400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Menu; 410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.MenuItem; 427e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Tokiimport android.view.MotionEvent; 430c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.View; 440c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.View.MeasureSpec; 4530f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Tokiimport android.view.View.OnLayoutChangeListener; 46f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Tokiimport android.view.ViewConfiguration; 470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.ViewGroup; 48517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.ViewTreeObserver; 490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Window; 50517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.WindowManager; 51517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.Animation; 52517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.AnimationSet; 537e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Tokiimport android.view.animation.AnimationUtils; 547e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Tokiimport android.view.animation.Interpolator; 55484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinirimport android.view.animation.Transformation; 56517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.ArrayAdapter; 570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.ImageButton; 58b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Tokiimport android.widget.ImageView; 590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.LinearLayout; 60517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.ListView; 610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.PopupWindow; 62517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.TextView; 630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 64484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinirimport com.android.internal.R; 65484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinirimport com.android.internal.util.Preconditions; 66484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir 670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.ArrayList; 689c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Tokiimport java.util.Comparator; 690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.LinkedList; 700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.List; 7146850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Tokiimport java.util.Objects; 72517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki/** 740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * A floating toolbar for showing contextual menu items. 750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * This view shows as many menu item buttons as can fit in the horizontal toolbar and the 760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * the remaining menu items in a vertical overflow view when the overflow button is clicked. 770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The horizontal toolbar morphs into the vertical overflow view. 780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokipublic final class FloatingToolbar { 800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 81517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki // This class is responsible for the public API of the floating toolbar. 82517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki // It delegates rendering operations to the FloatingToolbarPopup. 83517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 848a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki public static final String FLOATING_TOOLBAR_TAG = "floating_toolbar"; 858a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki 860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER = 8746850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki item -> false; 880c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 890c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private final Context mContext; 9030f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki private final Window mWindow; 910c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private final FloatingToolbarPopup mPopup; 920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private final Rect mContentRect = new Rect(); 94c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki private final Rect mPreviousContentRect = new Rect(); 950c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 960c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private Menu mMenu; 9746850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki private List<MenuItem> mShowingMenuItems = new ArrayList<>(); 980c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER; 990c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1000c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private int mSuggestedWidth; 101517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private boolean mWidthChanged = true; 1020c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 10330f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki private final OnLayoutChangeListener mOrientationChangeHandler = new OnLayoutChangeListener() { 10430f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki 10530f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki private final Rect mNewRect = new Rect(); 10630f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki private final Rect mOldRect = new Rect(); 10730f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki 1086bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri @Override 10930f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki public void onLayoutChange( 11030f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki View view, 11130f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki int newLeft, int newRight, int newTop, int newBottom, 11230f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki int oldLeft, int oldRight, int oldTop, int oldBottom) { 11330f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mNewRect.set(newLeft, newRight, newTop, newBottom); 11430f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mOldRect.set(oldLeft, oldRight, oldTop, oldBottom); 11530f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki if (mPopup.isShowing() && !mNewRect.equals(mOldRect)) { 1166bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri mWidthChanged = true; 1176bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri updateLayout(); 1186bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri } 1196bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri } 1206bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri }; 1216bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri 1220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1239c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki * Sorts the list of menu items to conform to certain requirements. 1249c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki */ 1259c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki private final Comparator<MenuItem> mMenuItemComparator = (menuItem1, menuItem2) -> { 1269c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki // Ensure the assist menu item is always the first item: 1279c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki if (menuItem1.getItemId() == android.R.id.textAssist) { 1289c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki return menuItem2.getItemId() == android.R.id.textAssist ? 0 : -1; 1299c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki } 1309c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki if (menuItem2.getItemId() == android.R.id.textAssist) { 1319c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki return 1; 1329c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki } 1339c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki 1349c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki // Order by SHOW_AS_ACTION type: 1359c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki if (menuItem1.requiresActionButton()) { 1369c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki return menuItem2.requiresActionButton() ? 0 : -1; 1379c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki } 1389c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki if (menuItem2.requiresActionButton()) { 1399c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki return 1; 1409c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki } 1419c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki if (menuItem1.requiresOverflow()) { 1429c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki return menuItem2.requiresOverflow() ? 0 : 1; 1439c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki } 1449c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki if (menuItem2.requiresOverflow()) { 1459c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki return -1; 1469c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki } 1479c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki 1489c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki // Order by order value: 1499c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki return menuItem1.getOrder() - menuItem2.getOrder(); 1509c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki }; 1519c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki 1529c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki /** 1530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Initializes a floating toolbar. 1540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 155c9c83a9ccbf8040c4130cb896e40019250d9d636Tarandeep Singh public FloatingToolbar(Window window) { 156c9c83a9ccbf8040c4130cb896e40019250d9d636Tarandeep Singh // TODO(b/65172902): Pass context in constructor when DecorView (and other callers) 157c9c83a9ccbf8040c4130cb896e40019250d9d636Tarandeep Singh // supports multi-display. 158c9c83a9ccbf8040c4130cb896e40019250d9d636Tarandeep Singh mContext = applyDefaultTheme(window.getContext()); 15930f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mWindow = Preconditions.checkNotNull(window); 160079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki mPopup = new FloatingToolbarPopup(mContext, window.getDecorView()); 1610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Sets the menu to be shown in this floating toolbar. 1650c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the 1660c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * toolbar. 1670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1680c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar setMenu(Menu menu) { 1690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mMenu = Preconditions.checkNotNull(menu); 1700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 1710c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1747270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Sets the custom listener for invocation of menu items in this floating toolbar. 1750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar setOnMenuItemClickListener( 1770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki MenuItem.OnMenuItemClickListener menuItemClickListener) { 1780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (menuItemClickListener != null) { 1790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mMenuItemClickListener = menuItemClickListener; 1800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } else { 1810c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER; 1820c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1830c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 1840c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1870c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Sets the content rectangle. This is the area of the interesting content that this toolbar 1880c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * should avoid obstructing. 1890c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the 1900c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * toolbar. 1910c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar setContentRect(Rect rect) { 1930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mContentRect.set(Preconditions.checkNotNull(rect)); 1940c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 1950c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1960c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1970c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1980c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Sets the suggested width of this floating toolbar. 1990c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The actual width will be about this size but there are no guarantees that it will be exactly 2000c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * the suggested width. 2010c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the 2020c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * toolbar. 2030c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 2040c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar setSuggestedWidth(int suggestedWidth) { 205517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki // Check if there's been a substantial width spec change. 206517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int difference = Math.abs(suggestedWidth - mSuggestedWidth); 207517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mWidthChanged = difference > (mSuggestedWidth * 0.2); 208517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 2090c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mSuggestedWidth = suggestedWidth; 2100c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 2110c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2130c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 2140c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Shows this floating toolbar. 2150c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 2160c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar show() { 21730f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki registerOrientationHandler(); 21830f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki doShow(); 2190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 2200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 2230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Updates this floating toolbar to reflect recent position and view updates. 2240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * NOTE: This method is a no-op if the toolbar isn't showing. 2250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 2260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar updateLayout() { 2270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (mPopup.isShowing()) { 22830f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki doShow(); 2290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 2310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 2340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Dismisses this floating toolbar. 2350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 2360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public void dismiss() { 23730f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki unregisterOrientationHandler(); 2380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mPopup.dismiss(); 2390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 2427270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Hides this floating toolbar. This is a no-op if the toolbar is not showing. 2437270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Use {@link #isHidden()} to distinguish between a hidden and a dismissed toolbar. 2447270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 2457270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public void hide() { 2467270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mPopup.hide(); 2477270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 2487270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 2497270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 2507270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Returns {@code true} if this toolbar is currently showing. {@code false} otherwise. 2510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 2520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public boolean isShowing() { 2530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return mPopup.isShowing(); 2540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 2577270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Returns {@code true} if this toolbar is currently hidden. {@code false} otherwise. 2587270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 2597270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public boolean isHidden() { 2607270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki return mPopup.isHidden(); 2617270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 2627270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 26329cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki /** 26429cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * If this is set to true, the action mode view will dismiss itself on touch events outside of 26529cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * its window. If the toolbar is already showing, it will be re-shown so that this setting takes 26629cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * effect immediately. 26729cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * 26829cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * @param outsideTouchable whether or not this action mode is "outside touchable" 26929cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * @param onDismiss optional. Sets a callback for when this action mode popup dismisses itself 27029cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki */ 27129cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki public void setOutsideTouchable( 27229cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki boolean outsideTouchable, @Nullable PopupWindow.OnDismissListener onDismiss) { 27329cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki if (mPopup.setOutsideTouchable(outsideTouchable, onDismiss) && isShowing()) { 27429cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki dismiss(); 27529cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki doShow(); 27629cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki } 27729cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki } 27829cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki 27930f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki private void doShow() { 28030f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu); 2819c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki menuItems.sort(mMenuItemComparator); 28230f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki if (!isCurrentlyShowing(menuItems) || mWidthChanged) { 28330f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mPopup.dismiss(); 28430f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); 28546850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki mShowingMenuItems = menuItems; 28630f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki } 28730f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki if (!mPopup.isShowing()) { 28830f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mPopup.show(mContentRect); 28930f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki } else if (!mPreviousContentRect.equals(mContentRect)) { 29030f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mPopup.updateCoordinates(mContentRect); 29130f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki } 29230f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mWidthChanged = false; 29330f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mPreviousContentRect.set(mContentRect); 29430f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki } 29530f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki 2967270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 297517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Returns true if this floating toolbar is currently showing the specified menu items. 2980c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 299517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private boolean isCurrentlyShowing(List<MenuItem> menuItems) { 30046850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki if (mShowingMenuItems == null || menuItems.size() != mShowingMenuItems.size()) { 30146850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki return false; 30246850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki } 30346850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki 30446850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki final int size = menuItems.size(); 30546850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki for (int i = 0; i < size; i++) { 30646850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki final MenuItem menuItem = menuItems.get(i); 30746850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki final MenuItem showingItem = mShowingMenuItems.get(i); 30846850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki if (menuItem.getItemId() != showingItem.getItemId() 30946850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki || !TextUtils.equals(menuItem.getTitle(), showingItem.getTitle()) 31046850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki || !Objects.equals(menuItem.getIcon(), showingItem.getIcon()) 31146850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki || menuItem.getGroupId() != showingItem.getGroupId()) { 31246850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki return false; 31346850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki } 31446850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki } 31546850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki 31646850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki return true; 3170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 3180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 3190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 3200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Returns the visible and enabled menu items in the specified menu. 3210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * This method is recursive. 3220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 3230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private List<MenuItem> getVisibleAndEnabledMenuItems(Menu menu) { 32446850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki List<MenuItem> menuItems = new ArrayList<>(); 3250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki for (int i = 0; (menu != null) && (i < menu.size()); i++) { 3260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki MenuItem menuItem = menu.getItem(i); 3270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (menuItem.isVisible() && menuItem.isEnabled()) { 3280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki Menu subMenu = menuItem.getSubMenu(); 3290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (subMenu != null) { 3300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki menuItems.addAll(getVisibleAndEnabledMenuItems(subMenu)); 3310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } else { 3320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki menuItems.add(menuItem); 3330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 3340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 3350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 3360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return menuItems; 3370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 3380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 33930f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki private void registerOrientationHandler() { 34030f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki unregisterOrientationHandler(); 34130f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mWindow.getDecorView().addOnLayoutChangeListener(mOrientationChangeHandler); 34230f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki } 34330f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki 34430f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki private void unregisterOrientationHandler() { 34530f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki mWindow.getDecorView().removeOnLayoutChangeListener(mOrientationChangeHandler); 34630f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki } 34730f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki 3480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 3490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 350517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * A popup window used by the floating toolbar. 351517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 352517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * This class is responsible for the rendering/animation of the floating toolbar. 3537e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * It holds 2 panels (i.e. main panel and overflow panel) and an overflow button 3547e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * to transition between panels. 3550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 356517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static final class FloatingToolbarPopup { 3570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 3587e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /* Minimum and maximum number of items allowed in the overflow. */ 3597e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static final int MIN_OVERFLOW_SIZE = 2; 3607e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static final int MAX_OVERFLOW_SIZE = 4; 3617e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 362079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki private final Context mContext; 3637e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final View mParent; // Parent for the popup window. 364517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final PopupWindow mPopupWindow; 3657e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 3667e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /* Margins between the popup window and it's content. */ 367f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki private final int mMarginHorizontal; 368f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki private final int mMarginVertical; 3690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 3707e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /* View components */ 3717e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final ViewGroup mContentContainer; // holds all contents. 3727e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final ViewGroup mMainPanel; // holds menu items that are initially displayed. 373cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki private final OverflowPanel mOverflowPanel; // holds menu items hidden in the overflow. 3747e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final ImageButton mOverflowButton; // opens/closes the overflow. 3757e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /* overflow button drawables. */ 3767e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Drawable mArrow; 3777e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Drawable mOverflow; 3787e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final AnimatedVectorDrawable mToArrow; 3797e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final AnimatedVectorDrawable mToOverflow; 3807e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 3817e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final OverflowPanelViewHelper mOverflowPanelViewHelper; 3827e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 3837e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /* Animation interpolators. */ 3847e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Interpolator mLogAccelerateInterpolator; 3857e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Interpolator mFastOutSlowInInterpolator; 3867e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Interpolator mLinearOutSlowInInterpolator; 3877e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Interpolator mFastOutLinearInInterpolator; 3887e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 3897e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /* Animations. */ 3907e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final AnimatorSet mShowAnimation; 3917270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private final AnimatorSet mDismissAnimation; 3927270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private final AnimatorSet mHideAnimation; 3937e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final AnimationSet mOpenOverflowAnimation; 3947e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final AnimationSet mCloseOverflowAnimation; 3957e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Animation.AnimationListener mOverflowAnimationListener; 396517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 3977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Rect mViewPortOnScreen = new Rect(); // portion of screen we can draw in. 3987e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Point mCoordsOnWindow = new Point(); // popup window coordinates. 3997e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /* Temporary data holders. Reset values before using. */ 4004b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa private final int[] mTmpCoords = new int[2]; 401ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 402517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final Region mTouchableRegion = new Region(); 403d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = 40446850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki info -> { 40546850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki info.contentInsets.setEmpty(); 40646850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki info.visibleInsets.setEmpty(); 40746850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki info.touchableRegion.set(mTouchableRegion); 40846850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki info.setTouchableInsets( 40946850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); 410d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki }; 411517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 412852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki private final int mLineHeight; 413852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki private final int mIconTextSpacing; 414852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki 4157e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /** 4167e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * @see OverflowPanelViewHelper#preparePopupContent(). 4177e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki */ 4187e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Runnable mPreparePopupContentRTLHelper = new Runnable() { 4197e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 4207e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public void run() { 4217e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setPanelsStatesAtRestingPosition(); 4227e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setContentAreaAsTouchableSurface(); 4237e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setAlpha(1); 4247e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 4257e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki }; 4267e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 4277270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private boolean mDismissed = true; // tracks whether this popup is dismissed or dismissing. 4287270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private boolean mHidden; // tracks whether this popup is hidden or hiding. 4290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 4307e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /* Calculated sizes for panels and overflow button. */ 4317e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Size mOverflowButtonSize; 4327e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private Size mOverflowPanelSize; // Should be null when there is no overflow. 4337e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private Size mMainPanelSize; 4347e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 4357e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /* Item click listeners */ 4367e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener; 4377e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final View.OnClickListener mMenuItemButtonOnClickListener = 4387e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki new View.OnClickListener() { 4397e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 4407e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public void onClick(View v) { 4417e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (v.getTag() instanceof MenuItem) { 4427e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOnMenuItemClickListener != null) { 4437e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOnMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag()); 4447e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 4457e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 4467e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 4477e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki }; 4487e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 4497e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private boolean mOpenOverflowUpwards; // Whether the overflow opens upwards or downwards. 4507e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private boolean mIsOverflowOpen; 4517e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 4527e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private int mTransitionDurationScale; // Used to scale the toolbar transition duration. 453517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 4540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 455517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Initializes a new floating toolbar popup. 4560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * 457517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param parent A parent view to get the {@link android.view.View#getWindowToken()} token 458517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * from. 4590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 460079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki public FloatingToolbarPopup(Context context, View parent) { 4610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mParent = Preconditions.checkNotNull(parent); 462079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki mContext = Preconditions.checkNotNull(context); 463079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki mContentContainer = createContentContainer(context); 4640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mPopupWindow = createPopupWindow(mContentContainer); 4657e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMarginHorizontal = parent.getResources() 4667e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); 4677e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMarginVertical = parent.getResources() 4687e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin); 469852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki mLineHeight = context.getResources() 470852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_height); 471852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki mIconTextSpacing = context.getResources() 47249ec54250f0cafd962c3c5f7f286875cf499483aAbodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_icon_text_spacing); 4737e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 4747e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Interpolators 4757e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mLogAccelerateInterpolator = new LogAccelerateInterpolator(); 4767e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator( 4777e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContext, android.R.interpolator.fast_out_slow_in); 4787e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator( 4797e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContext, android.R.interpolator.linear_out_slow_in); 4807e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator( 4817e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContext, android.R.interpolator.fast_out_linear_in); 4827e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 4837e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Drawables. Needed for views. 4847e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mArrow = mContext.getResources() 4857e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .getDrawable(R.drawable.ft_avd_tooverflow, mContext.getTheme()); 4867e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mArrow.setAutoMirrored(true); 4877e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflow = mContext.getResources() 4887e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .getDrawable(R.drawable.ft_avd_toarrow, mContext.getTheme()); 4897e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflow.setAutoMirrored(true); 4907e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mToArrow = (AnimatedVectorDrawable) mContext.getResources() 4917e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .getDrawable(R.drawable.ft_avd_toarrow_animation, mContext.getTheme()); 4927e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mToArrow.setAutoMirrored(true); 4937e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mToOverflow = (AnimatedVectorDrawable) mContext.getResources() 4947e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .getDrawable(R.drawable.ft_avd_tooverflow_animation, mContext.getTheme()); 4957e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mToOverflow.setAutoMirrored(true); 4967e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 4977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Views 4987e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton = createOverflowButton(); 4997e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButtonSize = measure(mOverflowButton); 5007e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel = createMainPanel(); 50149ec54250f0cafd962c3c5f7f286875cf499483aAbodunrinwa Toki mOverflowPanelViewHelper = new OverflowPanelViewHelper(mContext, mIconTextSpacing); 5027e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel = createOverflowPanel(); 5037e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 5047e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Animation. Need views. 5057e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowAnimationListener = createOverflowAnimationListener(); 5067e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOpenOverflowAnimation = new AnimationSet(true); 5077e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOpenOverflowAnimation.setAnimationListener(mOverflowAnimationListener); 5087e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mCloseOverflowAnimation = new AnimationSet(true); 5097e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mCloseOverflowAnimation.setAnimationListener(mOverflowAnimationListener); 5107e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mShowAnimation = createEnterAnimation(mContentContainer); 5117aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki mDismissAnimation = createExitAnimation( 512517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer, 5134ce050bd83b8c311d7cf7b50e0a36a28df68bc4aAbodunrinwa Toki 150, // startDelay 514517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki new AnimatorListenerAdapter() { 515517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 516517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onAnimationEnd(Animator animation) { 517517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mPopupWindow.dismiss(); 518b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.removeAllViews(); 519517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 520517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }); 5217aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki mHideAnimation = createExitAnimation( 5227270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mContentContainer, 5234ce050bd83b8c311d7cf7b50e0a36a28df68bc4aAbodunrinwa Toki 0, // startDelay 5247270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki new AnimatorListenerAdapter() { 5257270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki @Override 5267270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public void onAnimationEnd(Animator animation) { 5277270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mPopupWindow.dismiss(); 5287270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 5297270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki }); 530517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 531517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 532517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 53329cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * Makes this toolbar "outside touchable" and sets the onDismissListener. 53429cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * This will take effect the next time the toolbar is re-shown. 53529cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * 53629cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * @param outsideTouchable if true, the popup will be made "outside touchable" and 53729cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * "non focusable". The reverse will happen if false. 53829cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * @param onDismiss 53929cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * 54029cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * @return true if the "outsideTouchable" setting was modified. Otherwise returns false 54129cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * 54229cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * @see PopupWindow#setOutsideTouchable(boolean) 54329cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * @see PopupWindow#setFocusable(boolean) 54429cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki * @see PopupWindow.OnDismissListener 54529cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki */ 54629cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki public boolean setOutsideTouchable( 54729cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki boolean outsideTouchable, @Nullable PopupWindow.OnDismissListener onDismiss) { 54829cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki boolean ret = false; 54929cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki if (mPopupWindow.isOutsideTouchable() ^ outsideTouchable) { 55029cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki mPopupWindow.setOutsideTouchable(outsideTouchable); 55129cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki mPopupWindow.setFocusable(!outsideTouchable); 55229cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki ret = true; 55329cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki } 55429cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki mPopupWindow.setOnDismissListener(onDismiss); 55529cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki return ret; 55629cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki } 55729cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki 55829cb76849c94bdbd95439e372360a51720c6b067Abodunrinwa Toki /** 559517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Lays out buttons for the specified menu items. 5607e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * Requires a subsequent call to {@link #show()} to show the items. 561517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 5626c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki public void layoutMenuItems( 5636c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki List<MenuItem> menuItems, 5646c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki MenuItem.OnMenuItemClickListener menuItemClickListener, 5656c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki int suggestedWidth) { 5667e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOnMenuItemClickListener = menuItemClickListener; 5677e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki cancelOverflowAnimations(); 5687e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki clearPanels(); 5697e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki menuItems = layoutMainPanelItems(menuItems, getAdjustedToolbarWidth(suggestedWidth)); 5707e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (!menuItems.isEmpty()) { 5717e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Add remaining items to the overflow. 5727e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki layoutOverflowPanelItems(menuItems); 573517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 574517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki updatePopupSize(); 5750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 5760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 5770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 5780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Shows this popup at the specified coordinates. 5790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. 5800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 581bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa public void show(Rect contentRectOnScreen) { 582bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa Preconditions.checkNotNull(contentRectOnScreen); 583ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 5840c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (isShowing()) { 5850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return; 5860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 5870c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 5887270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHidden = false; 5897270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mDismissed = false; 5900ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki cancelDismissAndHideAnimations(); 5910ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki cancelOverflowAnimations(); 592ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 593bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa refreshCoordinatesAndOverflowDirection(contentRectOnScreen); 594517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki preparePopupContent(); 5954b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // We need to specify the position in window coordinates. 596bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can 5977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // specify the popup position in screen coordinates. 5987e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mPopupWindow.showAtLocation( 5997e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x, mCoordsOnWindow.y); 600d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki setTouchableSurfaceInsetsComputer(); 6017270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki runShowAnimation(); 6020c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 6030c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 6040c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 6050c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op. 6060c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 6070c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public void dismiss() { 6080ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki if (mDismissed) { 6090c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return; 6100c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 6110c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 6127270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHidden = false; 6137270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mDismissed = true; 6140ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki mHideAnimation.cancel(); 6157e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 6167270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki runDismissAnimation(); 6177270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki setZeroTouchableSurface(); 6187270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 6197270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 6207270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 6217270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Hides this popup. This is a no-op if this popup is not showing. 6227270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup. 6237270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 6247270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public void hide() { 6257270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki if (!isShowing()) { 6267270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki return; 6277270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 6287270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 6297270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHidden = true; 6307270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki runHideAnimation(); 631517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki setZeroTouchableSurface(); 6320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 6330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 6340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 6350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Returns {@code true} if this popup is currently showing. {@code false} otherwise. 6360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 6370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public boolean isShowing() { 638c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki return !mDismissed && !mHidden; 6397270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 6407270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 6417270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 6427270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Returns {@code true} if this popup is currently hidden. {@code false} otherwise. 6437270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 6447270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public boolean isHidden() { 6457270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki return mHidden; 6460c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 6470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 6480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 6490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Updates the coordinates of this popup. 6500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. 6517270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * This is a no-op if this popup is not showing. 6520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 653bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa public void updateCoordinates(Rect contentRectOnScreen) { 654bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa Preconditions.checkNotNull(contentRectOnScreen); 655ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 656c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki if (!isShowing() || !mPopupWindow.isShowing()) { 657517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return; 6580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 659517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 6600ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki cancelOverflowAnimations(); 661bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa refreshCoordinatesAndOverflowDirection(contentRectOnScreen); 662517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki preparePopupContent(); 6634b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // We need to specify the position in window coordinates. 664bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can 6657e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // specify the popup position in screen coordinates. 6667e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mPopupWindow.update( 6677e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mCoordsOnWindow.x, mCoordsOnWindow.y, 6687e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mPopupWindow.getWidth(), mPopupWindow.getHeight()); 6690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 6700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 671bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) { 6726d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki refreshViewPort(); 673e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki 67451a8af680b35e4d77786f277a3f06c13246a9d98Abodunrinwa Toki // Initialize x ensuring that the toolbar isn't rendered behind the nav bar in 67551a8af680b35e4d77786f277a3f06c13246a9d98Abodunrinwa Toki // landscape. 67651a8af680b35e4d77786f277a3f06c13246a9d98Abodunrinwa Toki final int x = Math.min( 67751a8af680b35e4d77786f277a3f06c13246a9d98Abodunrinwa Toki contentRectOnScreen.centerX() - mPopupWindow.getWidth() / 2, 67851a8af680b35e4d77786f277a3f06c13246a9d98Abodunrinwa Toki mViewPortOnScreen.right - mPopupWindow.getWidth()); 6797e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 6807e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int y; 681e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki 6827e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int availableHeightAboveContent = 6837e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki contentRectOnScreen.top - mViewPortOnScreen.top; 6847e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int availableHeightBelowContent = 6857e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mViewPortOnScreen.bottom - contentRectOnScreen.bottom; 6869ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki 6877e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int margin = 2 * mMarginVertical; 688852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki final int toolbarHeightWithVerticalMargin = mLineHeight + margin; 6899ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki 6907e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (!hasOverflow()) { 6917e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (availableHeightAboveContent >= toolbarHeightWithVerticalMargin) { 6926d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the top of the content. 6937e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki y = contentRectOnScreen.top - toolbarHeightWithVerticalMargin; 6947e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else if (availableHeightBelowContent >= toolbarHeightWithVerticalMargin) { 6956d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the bottom of the content. 696bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.bottom; 697852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki } else if (availableHeightBelowContent >= mLineHeight) { 6989ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // Just enough space to fit the toolbar with no vertical margins. 699bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.bottom - mMarginVertical; 7006d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } else { 7016d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Not enough space. Prefer to position as high as possible. 7026d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki y = Math.max( 703bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa mViewPortOnScreen.top, 7047e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki contentRectOnScreen.top - toolbarHeightWithVerticalMargin); 7056d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } 7067e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 7077e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Has an overflow. 7087e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int minimumOverflowHeightWithMargin = 7097e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki calculateOverflowHeight(MIN_OVERFLOW_SIZE) + margin; 7107e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int availableHeightThroughContentDown = mViewPortOnScreen.bottom - 7117e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki contentRectOnScreen.top + toolbarHeightWithVerticalMargin; 7127e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int availableHeightThroughContentUp = contentRectOnScreen.bottom - 7137e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mViewPortOnScreen.top + toolbarHeightWithVerticalMargin; 7149ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki 7159ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki if (availableHeightAboveContent >= minimumOverflowHeightWithMargin) { 7166d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the top of the content rect for the overflow. 7176d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Position above and open upwards. 7189ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki updateOverflowHeight(availableHeightAboveContent - margin); 7197e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki y = contentRectOnScreen.top - mPopupWindow.getHeight(); 7207e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOpenOverflowUpwards = true; 7217e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else if (availableHeightAboveContent >= toolbarHeightWithVerticalMargin 7229ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki && availableHeightThroughContentDown >= minimumOverflowHeightWithMargin) { 7236d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the top of the content rect for the main panel 7246d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // but not the overflow. 7256d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Position above but open downwards. 7269ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki updateOverflowHeight(availableHeightThroughContentDown - margin); 7277e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki y = contentRectOnScreen.top - toolbarHeightWithVerticalMargin; 7287e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOpenOverflowUpwards = false; 7299ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki } else if (availableHeightBelowContent >= minimumOverflowHeightWithMargin) { 7306d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the bottom of the content rect for the overflow. 7316d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Position below and open downwards. 7329ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki updateOverflowHeight(availableHeightBelowContent - margin); 733bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.bottom; 7347e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOpenOverflowUpwards = false; 7357e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else if (availableHeightBelowContent >= toolbarHeightWithVerticalMargin 736bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa && mViewPortOnScreen.height() >= minimumOverflowHeightWithMargin) { 7379ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // There is enough space at the bottom of the content rect for the main panel 7389ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // but not the overflow. 7399ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // Position below but open upwards. 7409ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki updateOverflowHeight(availableHeightThroughContentUp - margin); 7417e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki y = contentRectOnScreen.bottom + toolbarHeightWithVerticalMargin - 7427e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mPopupWindow.getHeight(); 7437e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOpenOverflowUpwards = true; 7446d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } else { 7456d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Not enough space. 7469ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // Position at the top of the view port and open downwards. 747bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa updateOverflowHeight(mViewPortOnScreen.height() - margin); 748bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = mViewPortOnScreen.top; 7497e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOpenOverflowUpwards = false; 7506d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } 751ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 7526d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki 7534b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // We later specify the location of PopupWindow relative to the attached window. 7544b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // The idea here is that 1) we can get the location of a View in both window coordinates 7554b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // and screen coordiantes, where the offset between them should be equal to the window 7564b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // origin, and 2) we can use an arbitrary for this calculation while calculating the 7574b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // location of the rootview is supposed to be least expensive. 7584b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can avoid 7594b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // the following calculation. 7604b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa mParent.getRootView().getLocationOnScreen(mTmpCoords); 7614b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int rootViewLeftOnScreen = mTmpCoords[0]; 7624b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int rootViewTopOnScreen = mTmpCoords[1]; 7634b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa mParent.getRootView().getLocationInWindow(mTmpCoords); 7644b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int rootViewLeftOnWindow = mTmpCoords[0]; 7654b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int rootViewTopOnWindow = mTmpCoords[1]; 7664b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int windowLeftOnScreen = rootViewLeftOnScreen - rootViewLeftOnWindow; 7674b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int windowTopOnScreen = rootViewTopOnScreen - rootViewTopOnWindow; 76851a8af680b35e4d77786f277a3f06c13246a9d98Abodunrinwa Toki mCoordsOnWindow.set( 76951a8af680b35e4d77786f277a3f06c13246a9d98Abodunrinwa Toki Math.max(0, x - windowLeftOnScreen), Math.max(0, y - windowTopOnScreen)); 770ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 771ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 7720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 7737270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Performs the "show" animation on the floating popup. 7747270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 7757270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private void runShowAnimation() { 7767e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mShowAnimation.start(); 7777270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 7787270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 7797270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 7807270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Performs the "dismiss" animation on the floating popup. 7810c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 7827270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private void runDismissAnimation() { 7837270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mDismissAnimation.start(); 7840c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 7850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 7860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 7877270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Performs the "hide" animation on the floating popup. 7880c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 7897270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private void runHideAnimation() { 7907270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHideAnimation.start(); 7910c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 7920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 7930ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki private void cancelDismissAndHideAnimations() { 7947270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mDismissAnimation.cancel(); 7957270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHideAnimation.cancel(); 7960ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki } 7970ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki 7980ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki private void cancelOverflowAnimations() { 7997e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.clearAnimation(); 8007e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.animate().cancel(); 8017e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.animate().cancel(); 8027e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mToArrow.stop(); 8037e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mToOverflow.stop(); 804517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 805517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 806517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void openOverflow() { 8077e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int targetWidth = mOverflowPanelSize.getWidth(); 8087e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int targetHeight = mOverflowPanelSize.getHeight(); 809517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int startWidth = mContentContainer.getWidth(); 810517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int startHeight = mContentContainer.getHeight(); 811517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final float startY = mContentContainer.getY(); 8126c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki final float left = mContentContainer.getX(); 8136c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki final float right = left + mContentContainer.getWidth(); 814517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Animation widthAnimation = new Animation() { 815517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 816517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 817517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); 8187e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setWidth(mContentContainer, startWidth + deltaWidth); 81949482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki if (isInRTLMode()) { 8206c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki mContentContainer.setX(left); 8217e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 8227e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Lock the panels in place. 8237e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setX(0); 8247e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setX(0); 8256c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki } else { 8266c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki mContentContainer.setX(right - mContentContainer.getWidth()); 8277e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 8287e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Offset the panels' positions so they look like they're locked in place 8297e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // on the screen. 8307e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setX(mContentContainer.getWidth() - startWidth); 8317e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setX(mContentContainer.getWidth() - targetWidth); 8326c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki } 833517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 834517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 835517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Animation heightAnimation = new Animation() { 836517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 837517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 838517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight)); 8397e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setHeight(mContentContainer, startHeight + deltaHeight); 8407e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOpenOverflowUpwards) { 8417e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setY( 8427e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki startY - (mContentContainer.getHeight() - startHeight)); 8437e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki positionContentYCoordinatesIfOpeningOverflowUpwards(); 844517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 845517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 846517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 8477e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final float overflowButtonStartX = mOverflowButton.getX(); 84849482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki final float overflowButtonTargetX = isInRTLMode() ? 8497e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowButtonStartX + targetWidth - mOverflowButton.getWidth() : 8507e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowButtonStartX - targetWidth + mOverflowButton.getWidth(); 8517e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Animation overflowButtonAnimation = new Animation() { 8527e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 8537e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 8547e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki float overflowButtonX = overflowButtonStartX 8557e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki + interpolatedTime * (overflowButtonTargetX - overflowButtonStartX); 85649482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki float deltaContainerWidth = isInRTLMode() ? 8577e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 0 : 8587e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.getWidth() - startWidth; 8597e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki float actualOverflowButtonX = overflowButtonX + deltaContainerWidth; 8607e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setX(actualOverflowButtonX); 8617e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 8627e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki }; 8637e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki widthAnimation.setInterpolator(mLogAccelerateInterpolator); 8647e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki widthAnimation.setDuration(getAdjustedDuration(250)); 8657e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki heightAnimation.setInterpolator(mFastOutSlowInInterpolator); 8667e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki heightAnimation.setDuration(getAdjustedDuration(250)); 8677e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowButtonAnimation.setInterpolator(mFastOutSlowInInterpolator); 8687e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowButtonAnimation.setDuration(getAdjustedDuration(250)); 8697e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOpenOverflowAnimation.getAnimations().clear(); 870b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mOpenOverflowAnimation.getAnimations().clear(); 871b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mOpenOverflowAnimation.addAnimation(widthAnimation); 872b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mOpenOverflowAnimation.addAnimation(heightAnimation); 8737e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOpenOverflowAnimation.addAnimation(overflowButtonAnimation); 874b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.startAnimation(mOpenOverflowAnimation); 8757e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mIsOverflowOpen = true; 8767e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.animate() 8777e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .alpha(0).withLayer() 8787e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .setInterpolator(mLinearOutSlowInInterpolator) 8797e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .setDuration(250) 8807e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .start(); 8817e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setAlpha(1); // fadeIn in 0ms. 882517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 883517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 884517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void closeOverflow() { 8857e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int targetWidth = mMainPanelSize.getWidth(); 886517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int startWidth = mContentContainer.getWidth(); 8876c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki final float left = mContentContainer.getX(); 8886c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki final float right = left + mContentContainer.getWidth(); 889517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Animation widthAnimation = new Animation() { 890517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 891517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 892517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); 8937e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setWidth(mContentContainer, startWidth + deltaWidth); 89449482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki if (isInRTLMode()) { 8956c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki mContentContainer.setX(left); 8967e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 8977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Lock the panels in place. 8987e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setX(0); 8997e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setX(0); 9006c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki } else { 9016c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki mContentContainer.setX(right - mContentContainer.getWidth()); 9027e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 9037e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Offset the panels' positions so they look like they're locked in place 9047e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // on the screen. 9057e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setX(mContentContainer.getWidth() - targetWidth); 9067e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setX(mContentContainer.getWidth() - startWidth); 9076c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki } 908517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 909517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 9107e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int targetHeight = mMainPanelSize.getHeight(); 9117e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int startHeight = mContentContainer.getHeight(); 9127e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final float bottom = mContentContainer.getY() + mContentContainer.getHeight(); 913517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Animation heightAnimation = new Animation() { 914517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 915517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 916517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight)); 9177e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setHeight(mContentContainer, startHeight + deltaHeight); 9187e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOpenOverflowUpwards) { 919517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.setY(bottom - mContentContainer.getHeight()); 9207e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki positionContentYCoordinatesIfOpeningOverflowUpwards(); 921517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 922517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 923517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 9247e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final float overflowButtonStartX = mOverflowButton.getX(); 92549482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki final float overflowButtonTargetX = isInRTLMode() ? 9267e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowButtonStartX - startWidth + mOverflowButton.getWidth() : 9277e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowButtonStartX + startWidth - mOverflowButton.getWidth(); 9287e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Animation overflowButtonAnimation = new Animation() { 9297e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 9307e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 9317e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki float overflowButtonX = overflowButtonStartX 9327e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki + interpolatedTime * (overflowButtonTargetX - overflowButtonStartX); 93349482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki float deltaContainerWidth = isInRTLMode() ? 9347e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 0 : 9357e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.getWidth() - startWidth; 9367e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki float actualOverflowButtonX = overflowButtonX + deltaContainerWidth; 9377e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setX(actualOverflowButtonX); 9387e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 9397e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki }; 9407e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki widthAnimation.setInterpolator(mFastOutSlowInInterpolator); 9417e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki widthAnimation.setDuration(getAdjustedDuration(250)); 9427e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki heightAnimation.setInterpolator(mLogAccelerateInterpolator); 9437e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki heightAnimation.setDuration(getAdjustedDuration(250)); 9447e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowButtonAnimation.setInterpolator(mFastOutSlowInInterpolator); 9457e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowButtonAnimation.setDuration(getAdjustedDuration(250)); 946b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mCloseOverflowAnimation.getAnimations().clear(); 947b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mCloseOverflowAnimation.addAnimation(widthAnimation); 948b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mCloseOverflowAnimation.addAnimation(heightAnimation); 9497e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mCloseOverflowAnimation.addAnimation(overflowButtonAnimation); 950b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.startAnimation(mCloseOverflowAnimation); 9517e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mIsOverflowOpen = false; 9527e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.animate() 9537e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .alpha(1).withLayer() 9547e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .setInterpolator(mFastOutLinearInInterpolator) 9557e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .setDuration(100) 9567e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .start(); 9577e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.animate() 9587e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .alpha(0).withLayer() 9597e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .setInterpolator(mLinearOutSlowInInterpolator) 9607e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .setDuration(150) 9617e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .start(); 9627e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 9637e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 964f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki /** 965f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki * Defines the position of the floating toolbar popup panels when transition animation has 966f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki * stopped. 967f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki */ 9687e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private void setPanelsStatesAtRestingPosition() { 9697e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setEnabled(true); 970cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki mOverflowPanel.awakenScrollBars(); 9717e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 9727e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mIsOverflowOpen) { 9737e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Set open state. 9747e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final Size containerSize = mOverflowPanelSize; 9757e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setSize(mContentContainer, containerSize); 9767e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setAlpha(0); 9770cf648917fcbea6c91406566639294caacfa6fa1Abodunrinwa Toki mMainPanel.setVisibility(View.INVISIBLE); 9787e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setAlpha(1); 9790cf648917fcbea6c91406566639294caacfa6fa1Abodunrinwa Toki mOverflowPanel.setVisibility(View.VISIBLE); 9807e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setImageDrawable(mArrow); 9811d4e18340eea41235385be8c8e7f96cc6c25a59fPhil Weaver mOverflowButton.setContentDescription(mContext.getString( 9821d4e18340eea41235385be8c8e7f96cc6c25a59fPhil Weaver R.string.floating_toolbar_close_overflow_description)); 9837e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 9847e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Update x-coordinates depending on RTL state. 98549482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki if (isInRTLMode()) { 9867e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setX(mMarginHorizontal); // align left 9877e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setX(0); // align left 9887e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setX( // align right 9897e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki containerSize.getWidth() - mOverflowButtonSize.getWidth()); 9907e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setX(0); // align left 9917e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 9927e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setX( // align right 9930780f3a0733ea8ff4e8a93ca1263d92e24a6e9bbAbodunrinwa Toki mPopupWindow.getWidth() - 9940780f3a0733ea8ff4e8a93ca1263d92e24a6e9bbAbodunrinwa Toki containerSize.getWidth() - mMarginHorizontal); 9957e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setX(-mContentContainer.getX()); // align right 9967e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setX(0); // align left 9977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setX(0); // align left 9987e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 999b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki 10007e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Update y-coordinates depending on overflow's open direction. 10017e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOpenOverflowUpwards) { 10027e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setY(mMarginVertical); // align top 10037e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setY( // align bottom 10047e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki containerSize.getHeight() - mContentContainer.getHeight()); 10057e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setY( // align bottom 10067e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki containerSize.getHeight() - mOverflowButtonSize.getHeight()); 10077e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setY(0); // align top 10087e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 10097e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // opens downwards. 10107e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setY(mMarginVertical); // align top 10117e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setY(0); // align top 10127e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setY(0); // align top 10137e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom 10147e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 10156cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki } else { 10166be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki // Overflow not open. Set closed state. 10176be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki final Size containerSize = mMainPanelSize; 10186be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki setSize(mContentContainer, containerSize); 10196be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki mMainPanel.setAlpha(1); 10200cf648917fcbea6c91406566639294caacfa6fa1Abodunrinwa Toki mMainPanel.setVisibility(View.VISIBLE); 10216be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki mOverflowPanel.setAlpha(0); 10220cf648917fcbea6c91406566639294caacfa6fa1Abodunrinwa Toki mOverflowPanel.setVisibility(View.INVISIBLE); 10236be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki mOverflowButton.setImageDrawable(mOverflow); 10241d4e18340eea41235385be8c8e7f96cc6c25a59fPhil Weaver mOverflowButton.setContentDescription(mContext.getString( 10251d4e18340eea41235385be8c8e7f96cc6c25a59fPhil Weaver R.string.floating_toolbar_open_overflow_description)); 10267e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 10276be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki if (hasOverflow()) { 10287e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Update x-coordinates depending on RTL state. 102949482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki if (isInRTLMode()) { 10307e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setX(mMarginHorizontal); // align left 10317e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setX(0); // align left 10327e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setX(0); // align left 10337e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setX(0); // align left 10347e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 10350780f3a0733ea8ff4e8a93ca1263d92e24a6e9bbAbodunrinwa Toki mContentContainer.setX( // align right 10360780f3a0733ea8ff4e8a93ca1263d92e24a6e9bbAbodunrinwa Toki mPopupWindow.getWidth() - 10370780f3a0733ea8ff4e8a93ca1263d92e24a6e9bbAbodunrinwa Toki containerSize.getWidth() - mMarginHorizontal); 10387e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setX(0); // align left 10397e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setX( // align right 10407e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki containerSize.getWidth() - mOverflowButtonSize.getWidth()); 10417e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setX( // align right 10427e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki containerSize.getWidth() - mOverflowPanelSize.getWidth()); 10437e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 10447e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 10457e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Update y-coordinates depending on overflow's open direction. 10467e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOpenOverflowUpwards) { 10477e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setY( // align bottom 10487e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMarginVertical + 10497e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanelSize.getHeight() - containerSize.getHeight()); 10507e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setY(0); // align top 10517e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setY(0); // align top 10527e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setY( // align bottom 10537e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki containerSize.getHeight() - mOverflowPanelSize.getHeight()); 10547e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 10557e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // opens downwards. 10567e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setY(mMarginVertical); // align top 10577e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setY(0); // align top 10587e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setY(0); // align top 10597e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setY(mOverflowButtonSize.getHeight()); // align bottom 10607e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 10617e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 10626be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki // No overflow. 10636be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki mContentContainer.setX(mMarginHorizontal); // align left 10646be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki mContentContainer.setY(mMarginVertical); // align top 10656be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki mMainPanel.setX(0); // align left 10666be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki mMainPanel.setY(0); // align top 10677e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 10686cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki } 1069517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1070517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 10717e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private void updateOverflowHeight(int suggestedHeight) { 10727e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (hasOverflow()) { 10737e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int maxItemSize = (suggestedHeight - mOverflowButtonSize.getHeight()) / 1074852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki mLineHeight; 10757e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int newHeight = calculateOverflowHeight(maxItemSize); 10767e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOverflowPanelSize.getHeight() != newHeight) { 10777e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanelSize = new Size(mOverflowPanelSize.getWidth(), newHeight); 1078ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 10797e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setSize(mOverflowPanel, mOverflowPanelSize); 10807e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mIsOverflowOpen) { 10817e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setSize(mContentContainer, mOverflowPanelSize); 10827e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOpenOverflowUpwards) { 10837e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int deltaHeight = mOverflowPanelSize.getHeight() - newHeight; 10847e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setY(mContentContainer.getY() + deltaHeight); 10857e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setY(mOverflowButton.getY() - deltaHeight); 10867e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 10877e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 10887e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setSize(mContentContainer, mMainPanelSize); 1089ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 10907e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki updatePopupSize(); 1091ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 1092ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 1093ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 1094517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void updatePopupSize() { 1095517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int width = 0; 1096517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int height = 0; 10977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mMainPanelSize != null) { 10987e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki width = Math.max(width, mMainPanelSize.getWidth()); 10997e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki height = Math.max(height, mMainPanelSize.getHeight()); 1100517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 11017e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOverflowPanelSize != null) { 11027e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki width = Math.max(width, mOverflowPanelSize.getWidth()); 11037e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki height = Math.max(height, mOverflowPanelSize.getHeight()); 1104517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1105f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mPopupWindow.setWidth(width + mMarginHorizontal * 2); 1106f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mPopupWindow.setHeight(height + mMarginVertical * 2); 11077e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki maybeComputeTransitionDurationScale(); 1108517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1109517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1110e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki private void refreshViewPort() { 1111bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa mParent.getWindowVisibleDisplayFrame(mViewPortOnScreen); 1112e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki } 1113e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki 11147e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private int getAdjustedToolbarWidth(int suggestedWidth) { 1115e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki int width = suggestedWidth; 1116e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki refreshViewPort(); 1117bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa int maximumWidth = mViewPortOnScreen.width() - 2 * mParent.getResources() 1118e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); 1119e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki if (width <= 0) { 1120e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki width = mParent.getResources() 1121e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_preferred_width); 1122e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki } 1123e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki return Math.min(width, maximumWidth); 1124e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki } 1125e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki 1126517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1127517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Sets the touchable region of this popup to be zero. This means that all touch events on 1128517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * this popup will go through to the surface behind it. 1129517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1130517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void setZeroTouchableSurface() { 1131517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mTouchableRegion.setEmpty(); 1132517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1133517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1134517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1135517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Sets the touchable region of this popup to be the area occupied by its content. 1136517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1137517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void setContentAreaAsTouchableSurface() { 11387e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Preconditions.checkNotNull(mMainPanelSize); 11397e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int width; 11407e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int height; 11417e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mIsOverflowOpen) { 11427e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Preconditions.checkNotNull(mOverflowPanelSize); 11437e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki width = mOverflowPanelSize.getWidth(); 11447e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki height = mOverflowPanelSize.getHeight(); 11457e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 11467e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki width = mMainPanelSize.getWidth(); 11477e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki height = mMainPanelSize.getHeight(); 1148517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1149517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mTouchableRegion.set( 1150517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki (int) mContentContainer.getX(), 1151517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki (int) mContentContainer.getY(), 1152517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki (int) mContentContainer.getX() + width, 1153517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki (int) mContentContainer.getY() + height); 1154517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1155d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki 1156d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki /** 1157d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki * Make the touchable area of this popup be the area specified by mTouchableRegion. 1158d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki * This should be called after the popup window has been dismissed (dismiss/hide) 1159d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki * and is probably being re-shown with a new content root view. 1160d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki */ 1161d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki private void setTouchableSurfaceInsetsComputer() { 1162d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki ViewTreeObserver viewTreeObserver = mPopupWindow.getContentView() 1163d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki .getRootView() 1164d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki .getViewTreeObserver(); 1165d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki viewTreeObserver.removeOnComputeInternalInsetsListener(mInsetsComputer); 1166d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer); 1167d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki } 11686cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki 116949482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki private boolean isInRTLMode() { 117049482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki return mContext.getApplicationInfo().hasRtlSupport() 117149482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki && mContext.getResources().getConfiguration().getLayoutDirection() 117249482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki == View.LAYOUT_DIRECTION_RTL; 11736cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki } 1174517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 11757e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private boolean hasOverflow() { 11767e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return mOverflowPanelSize != null; 1177517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1178517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 11790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1180517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Fits as many menu items in the main panel and returns a list of the menu items that 1181517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * were not fit in. 1182517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 1183517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @return The menu items that are not included in this main panel. 11840c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 11857e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public List<MenuItem> layoutMainPanelItems( 11867e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki List<MenuItem> menuItems, final int toolbarWidth) { 1187ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki Preconditions.checkNotNull(menuItems); 1188ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 1189517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int availableWidth = toolbarWidth; 1190484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir 1191484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir final LinkedList<MenuItem> remainingMenuItems = new LinkedList<>(); 1192484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir // add the overflow menu items to the end of the remainingMenuItems list. 1193484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir final LinkedList<MenuItem> overflowMenuItems = new LinkedList(); 1194484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir for (MenuItem menuItem : menuItems) { 11959c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki if (menuItem.getItemId() != android.R.id.textAssist 11969c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki && menuItem.requiresOverflow()) { 1197484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir overflowMenuItems.add(menuItem); 1198484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir } else { 1199484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir remainingMenuItems.add(menuItem); 1200484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir } 1201484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir } 1202484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir remainingMenuItems.addAll(overflowMenuItems); 1203517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 12047e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.removeAllViews(); 12056be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki mMainPanel.setPaddingRelative(0, 0, 0, 0); 1206517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 12075fedfb8d469ea5d1911be3ec44c2c19e7946a6e3Abodunrinwa Toki int lastGroupId = -1; 1208517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki boolean isFirstItem = true; 1209517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki while (!remainingMenuItems.isEmpty()) { 1210517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final MenuItem menuItem = remainingMenuItems.peek(); 1211484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir 1212484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir // if this is the first item, regardless of requiresOverflow(), it should be 1213484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir // displayed on the main panel. Otherwise all items including this one will be 1214484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir // overflow items, and should be displayed in overflow panel. 1215484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir if(!isFirstItem && menuItem.requiresOverflow()) { 1216484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir break; 1217484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir } 1218484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir 12199c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki final boolean showIcon = isFirstItem && menuItem.getItemId() == R.id.textAssist; 12209c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki final View menuItemButton = createMenuItemButton( 12219c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki mContext, menuItem, mIconTextSpacing, showIcon); 122266d41f87ead4f4d27bcb1a610c4130130e4b4bdcMihai Popa if (!showIcon && menuItemButton instanceof LinearLayout) { 122366d41f87ead4f4d27bcb1a610c4130130e4b4bdcMihai Popa ((LinearLayout) menuItemButton).setGravity(Gravity.CENTER); 122466d41f87ead4f4d27bcb1a610c4130130e4b4bdcMihai Popa } 1225517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1226f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki // Adding additional start padding for the first button to even out button spacing. 1227517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (isFirstItem) { 1228f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki menuItemButton.setPaddingRelative( 1229f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki (int) (1.5 * menuItemButton.getPaddingStart()), 1230517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.getPaddingTop(), 1231f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki menuItemButton.getPaddingEnd(), 1232517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.getPaddingBottom()); 1233517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1234517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1235f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki // Adding additional end padding for the last button to even out button spacing. 12365fedfb8d469ea5d1911be3ec44c2c19e7946a6e3Abodunrinwa Toki boolean isLastItem = remainingMenuItems.size() == 1; 12375fedfb8d469ea5d1911be3ec44c2c19e7946a6e3Abodunrinwa Toki if (isLastItem) { 1238f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki menuItemButton.setPaddingRelative( 1239f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki menuItemButton.getPaddingStart(), 1240517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.getPaddingTop(), 1241f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki (int) (1.5 * menuItemButton.getPaddingEnd()), 1242517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.getPaddingBottom()); 1243517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1244517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1245517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 12469c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki final int menuItemButtonWidth = Math.min( 12479c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki menuItemButton.getMeasuredWidth(), toolbarWidth); 12485fedfb8d469ea5d1911be3ec44c2c19e7946a6e3Abodunrinwa Toki 12497e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Check if we can fit an item while reserving space for the overflowButton. 12509c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki final boolean canFitWithOverflow = 12515fedfb8d469ea5d1911be3ec44c2c19e7946a6e3Abodunrinwa Toki menuItemButtonWidth <= 125266d41f87ead4f4d27bcb1a610c4130130e4b4bdcMihai Popa availableWidth - mOverflowButtonSize.getWidth(); 12539c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki final boolean canFitNoOverflow = 125466d41f87ead4f4d27bcb1a610c4130130e4b4bdcMihai Popa isLastItem && menuItemButtonWidth <= availableWidth; 12557e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (canFitWithOverflow || canFitNoOverflow) { 1256b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki setButtonTagAndClickListener(menuItemButton, menuItem); 12572a00f9807c4f447aa9fd4005b40885d80a7b1635Vladislav Kaznacheev // Set tooltips for main panel items, but not overflow items (b/35726766). 12582a00f9807c4f447aa9fd4005b40885d80a7b1635Vladislav Kaznacheev menuItemButton.setTooltipText(menuItem.getTooltipText()); 12597e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.addView(menuItemButton); 12605fedfb8d469ea5d1911be3ec44c2c19e7946a6e3Abodunrinwa Toki final ViewGroup.LayoutParams params = menuItemButton.getLayoutParams(); 126166d41f87ead4f4d27bcb1a610c4130130e4b4bdcMihai Popa params.width = menuItemButtonWidth; 1262517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.setLayoutParams(params); 126366d41f87ead4f4d27bcb1a610c4130130e4b4bdcMihai Popa availableWidth -= menuItemButtonWidth; 1264517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki remainingMenuItems.pop(); 1265517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } else { 1266517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki break; 1267517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 12685fedfb8d469ea5d1911be3ec44c2c19e7946a6e3Abodunrinwa Toki lastGroupId = menuItem.getGroupId(); 12695fedfb8d469ea5d1911be3ec44c2c19e7946a6e3Abodunrinwa Toki isFirstItem = false; 1270517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1271484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir 1272484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir if (!remainingMenuItems.isEmpty()) { 1273484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir // Reserve space for overflowButton. 1274484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir mMainPanel.setPaddingRelative(0, 0, mOverflowButtonSize.getWidth(), 0); 1275484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir } 1276484c2e2fbec02209337bb86fc99b8b253bc06f99Siyamed Sinir 12777e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanelSize = measure(mMainPanel); 1278517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return remainingMenuItems; 1279517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1280517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 12817e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private void layoutOverflowPanelItems(List<MenuItem> menuItems) { 12827e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki ArrayAdapter<MenuItem> overflowPanelAdapter = 12837e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki (ArrayAdapter<MenuItem>) mOverflowPanel.getAdapter(); 12847e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowPanelAdapter.clear(); 12857e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int size = menuItems.size(); 12867e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki for (int i = 0; i < size; i++) { 12877e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowPanelAdapter.add(menuItems.get(i)); 12887e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 12897e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setAdapter(overflowPanelAdapter); 12907e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOpenOverflowUpwards) { 12917e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setY(0); 12927e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 12937e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setY(mOverflowButtonSize.getHeight()); 12947e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 12950c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 12967e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki int width = Math.max(getOverflowWidth(), mOverflowButtonSize.getWidth()); 12977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki int height = calculateOverflowHeight(MAX_OVERFLOW_SIZE); 12987e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanelSize = new Size(width, height); 12997e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setSize(mOverflowPanel, mOverflowPanelSize); 13000c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 13010c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 13027e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /** 13037e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * Resets the content container and appropriately position it's panels. 13047e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki */ 13057e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private void preparePopupContent() { 13067e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.removeAllViews(); 13077e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 13087e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Add views in the specified order so they stack up as expected. 13097e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Order: overflowPanel, mainPanel, overflowButton. 13107e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (hasOverflow()) { 13117e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.addView(mOverflowPanel); 13127e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 13137e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.addView(mMainPanel); 13147e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (hasOverflow()) { 13157e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.addView(mOverflowButton); 13167e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 13177e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setPanelsStatesAtRestingPosition(); 13187e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setContentAreaAsTouchableSurface(); 1319517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 13207e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // The positioning of contents in RTL is wrong when the view is first rendered. 13217e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Hide the view and post a runnable to recalculate positions and render the view. 13227e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // TODO: Investigate why this happens and fix. 132349482f83e8d6a892bc8b084108bf05d82263772fAbodunrinwa Toki if (isInRTLMode()) { 13247e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.setAlpha(0); 13257e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.post(mPreparePopupContentRTLHelper); 13267e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 13270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 13280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 13290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 13307e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * Clears out the panels and their container. Resets their calculated sizes. 1331517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 13327e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private void clearPanels() { 13337e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanelSize = null; 13347e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanelSize = null; 13357e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mIsOverflowOpen = false; 13367e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.removeAllViews(); 13377e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki ArrayAdapter<MenuItem> overflowPanelAdapter = 13387e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki (ArrayAdapter<MenuItem>) mOverflowPanel.getAdapter(); 13397e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowPanelAdapter.clear(); 13407e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setAdapter(overflowPanelAdapter); 13417e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.removeAllViews(); 13427e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 13437e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 13447e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private void positionContentYCoordinatesIfOpeningOverflowUpwards() { 13457e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mOpenOverflowUpwards) { 13467e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanel.setY(mContentContainer.getHeight() - mMainPanelSize.getHeight()); 13477e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setY(mContentContainer.getHeight() - mOverflowButton.getHeight()); 13487e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.setY(mContentContainer.getHeight() - mOverflowPanelSize.getHeight()); 13497e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 13507e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 13517e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 13527e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private int getOverflowWidth() { 13537e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki int overflowWidth = 0; 13547e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final int count = mOverflowPanel.getAdapter().getCount(); 13557e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki for (int i = 0; i < count; i++) { 13567e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki MenuItem menuItem = (MenuItem) mOverflowPanel.getAdapter().getItem(i); 13577e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowWidth = 13587e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Math.max(mOverflowPanelViewHelper.calculateWidth(menuItem), overflowWidth); 13597e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 13607e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return overflowWidth; 13617e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 13627e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 13637e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private int calculateOverflowHeight(int maxItemSize) { 13647e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Maximum of 4 items, minimum of 2 if the overflow has to scroll. 13657e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki int actualSize = Math.min( 13667e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki MAX_OVERFLOW_SIZE, 13677e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Math.min( 13687e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Math.max(MIN_OVERFLOW_SIZE, maxItemSize), 13697e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowPanel.getCount())); 1370f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki int extension = 0; 1371f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki if (actualSize < mOverflowPanel.getCount()) { 1372f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki // The overflow will require scrolling to get to all the items. 1373f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki // Extend the height so that part of the hidden items is displayed. 1374852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki extension = (int) (mLineHeight * 0.5f); 1375f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki } 1376852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki return actualSize * mLineHeight 1377f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki + mOverflowButtonSize.getHeight() 1378f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki + extension; 1379517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1380b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki 1381b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki private void setButtonTagAndClickListener(View menuItemButton, MenuItem menuItem) { 1382852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki menuItemButton.setTag(menuItem); 1383852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener); 1384b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1385517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 13867e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /** 13877e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * NOTE: Use only in android.view.animation.* animations. Do not use in android.animation.* 13887e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * animations. See comment about this in the code. 13897e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki */ 13907e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private int getAdjustedDuration(int originalDuration) { 13917e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (mTransitionDurationScale < 150) { 13927e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // For smaller transition, decrease the time. 13937e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return Math.max(originalDuration - 50, 0); 13947e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else if (mTransitionDurationScale > 300) { 13957e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // For bigger transition, increase the time. 13967e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return originalDuration + 50; 13977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 1398517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 13997e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Scale the animation duration with getDurationScale(). This allows 14007e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // android.view.animation.* animations to scale just like android.animation.* animations 14017e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // when animator duration scale is adjusted in "Developer Options". 14027e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // For this reason, do not use this method for android.animation.* animations. 14037e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return (int) (originalDuration * ValueAnimator.getDurationScale()); 14047e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 1405517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 14067e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private void maybeComputeTransitionDurationScale() { 1407d1cd7fdedea0647056e34f43cb79a67819d20533Abodunrinwa Toki if (mMainPanelSize != null && mOverflowPanelSize != null) { 14087e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki int w = mMainPanelSize.getWidth() - mOverflowPanelSize.getWidth(); 14097e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki int h = mOverflowPanelSize.getHeight() - mMainPanelSize.getHeight(); 14107e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mTransitionDurationScale = (int) (Math.sqrt(w * w + h * h) / 14117e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContentContainer.getContext().getResources().getDisplayMetrics().density); 14127e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 14137e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 1414517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 14157e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private ViewGroup createMainPanel() { 14167e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki ViewGroup mainPanel = new LinearLayout(mContext) { 14177e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 14187e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 14197e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki if (isOverflowAnimating()) { 14207e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Update widthMeasureSpec to make sure that this view is not clipped 14217e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // as we offset it's coordinates with respect to it's parent. 14227e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki widthMeasureSpec = MeasureSpec.makeMeasureSpec( 14237e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mMainPanelSize.getWidth(), 14247e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki MeasureSpec.EXACTLY); 14257e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 14267e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki super.onMeasure(widthMeasureSpec, heightMeasureSpec); 14277e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 1428517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 14297e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 14307e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public boolean onInterceptTouchEvent(MotionEvent ev) { 14317e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Intercept the touch event while the overflow is animating. 14327e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return isOverflowAnimating(); 14337e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 14347e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki }; 14357e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return mainPanel; 14367e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 1437517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 14387e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private ImageButton createOverflowButton() { 14397e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final ImageButton overflowButton = (ImageButton) LayoutInflater.from(mContext) 14407e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki .inflate(R.layout.floating_popup_overflow_button, null); 14417e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowButton.setImageDrawable(mOverflow); 144246850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki overflowButton.setOnClickListener(v -> { 144346850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki if (mIsOverflowOpen) { 144446850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki overflowButton.setImageDrawable(mToOverflow); 144546850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki mToOverflow.start(); 144646850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki closeOverflow(); 144746850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki } else { 144846850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki overflowButton.setImageDrawable(mToArrow); 144946850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki mToArrow.start(); 145046850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki openOverflow(); 1451517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1452517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }); 14537e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return overflowButton; 14547e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 14557e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 1456cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki private OverflowPanel createOverflowPanel() { 1457cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki final OverflowPanel overflowPanel = new OverflowPanel(this); 14587e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowPanel.setLayoutParams(new ViewGroup.LayoutParams( 14597e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 14607e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowPanel.setDivider(null); 14617e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowPanel.setDividerHeight(0); 14627e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 14637e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final ArrayAdapter adapter = 14647e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki new ArrayAdapter<MenuItem>(mContext, 0) { 14657e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 14667e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public View getView(int position, View convertView, ViewGroup parent) { 14677e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return mOverflowPanelViewHelper.getView( 14687e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki getItem(position), mOverflowPanelSize.getWidth(), convertView); 14697e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 14707e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki }; 14717e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki overflowPanel.setAdapter(adapter); 1472517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 147346850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki overflowPanel.setOnItemClickListener((parent, view, position, id) -> { 147446850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki MenuItem menuItem = (MenuItem) overflowPanel.getAdapter().getItem(position); 147546850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki if (mOnMenuItemClickListener != null) { 147646850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki mOnMenuItemClickListener.onMenuItemClick(menuItem); 1477517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1478517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }); 1479517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 14807e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return overflowPanel; 1481517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1482517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 14837e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private boolean isOverflowAnimating() { 14847e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final boolean overflowOpening = mOpenOverflowAnimation.hasStarted() 14857e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki && !mOpenOverflowAnimation.hasEnded(); 14867e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki final boolean overflowClosing = mCloseOverflowAnimation.hasStarted() 14877e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki && !mCloseOverflowAnimation.hasEnded(); 14887e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return overflowOpening || overflowClosing; 1489517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1490517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 14917e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private Animation.AnimationListener createOverflowAnimationListener() { 14927e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Animation.AnimationListener listener = new Animation.AnimationListener() { 14937e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 14947e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public void onAnimationStart(Animation animation) { 14957e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Disable the overflow button while it's animating. 14967e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // It will be re-enabled when the animation stops. 14977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mOverflowButton.setEnabled(false); 14980cf648917fcbea6c91406566639294caacfa6fa1Abodunrinwa Toki // Ensure both panels have visibility turned on when the overflow animation 14990cf648917fcbea6c91406566639294caacfa6fa1Abodunrinwa Toki // starts. 15000cf648917fcbea6c91406566639294caacfa6fa1Abodunrinwa Toki mMainPanel.setVisibility(View.VISIBLE); 15010cf648917fcbea6c91406566639294caacfa6fa1Abodunrinwa Toki mOverflowPanel.setVisibility(View.VISIBLE); 15027e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 15037e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 15047e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 15057e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public void onAnimationEnd(Animation animation) { 15067e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // Posting this because it seems like this is called before the animation 15077e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki // actually ends. 150846850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki mContentContainer.post(() -> { 150946850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki setPanelsStatesAtRestingPosition(); 151046850fcaea40c63ba66dca8d492bc30b531ce104Abodunrinwa Toki setContentAreaAsTouchableSurface(); 15117e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki }); 15127e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 15137e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 15147e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 15157e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public void onAnimationRepeat(Animation animation) { 15167e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 15177e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki }; 15187e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return listener; 15190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 15200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 15217e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static Size measure(View view) { 15227e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Preconditions.checkState(view.getParent() == null); 15237e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 15247e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return new Size(view.getMeasuredWidth(), view.getMeasuredHeight()); 15250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 15260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 15277e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static void setSize(View view, int width, int height) { 15287e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki view.setMinimumWidth(width); 15297e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki view.setMinimumHeight(height); 15307e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki ViewGroup.LayoutParams params = view.getLayoutParams(); 15317e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki params = (params == null) ? new ViewGroup.LayoutParams(0, 0) : params; 15327e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki params.width = width; 15337e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki params.height = height; 15347e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki view.setLayoutParams(params); 1535ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 1536ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 15377e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static void setSize(View view, Size size) { 15387e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setSize(view, size.getWidth(), size.getHeight()); 15396d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } 15406d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki 15417e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static void setWidth(View view, int width) { 15427e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki ViewGroup.LayoutParams params = view.getLayoutParams(); 15437e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setSize(view, width, params.height); 1544517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1545517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 15467e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static void setHeight(View view, int height) { 15477e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki ViewGroup.LayoutParams params = view.getLayoutParams(); 15487e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki setSize(view, params.width, height); 1549517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1550517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1551517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1552cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki * A custom ListView for the overflow panel. 1553cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki */ 1554cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki private static final class OverflowPanel extends ListView { 1555cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki 1556cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki private final FloatingToolbarPopup mPopup; 1557cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki 1558cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki OverflowPanel(FloatingToolbarPopup popup) { 1559cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki super(Preconditions.checkNotNull(popup).mContext); 1560cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki this.mPopup = popup; 1561f0f4d73b5b0338a4c94f1ef1a5973b69bbbe5134Abodunrinwa Toki setScrollBarDefaultDelayBeforeFade(ViewConfiguration.getScrollDefaultDelay() * 3); 15628949faf0660d5c5e5479f164094f8761290824b7Abodunrinwa Toki setScrollIndicators(View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_BOTTOM); 1563cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki } 1564cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki 1565cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki @Override 1566cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1567cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki // Update heightMeasureSpec to make sure that this view is not clipped 1568cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki // as we offset it's coordinates with respect to it's parent. 1569cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki int height = mPopup.mOverflowPanelSize.getHeight() 1570cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki - mPopup.mOverflowButtonSize.getHeight(); 1571cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); 1572cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki super.onMeasure(widthMeasureSpec, heightMeasureSpec); 1573cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki } 1574cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki 1575cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki @Override 1576cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki public boolean dispatchTouchEvent(MotionEvent ev) { 1577cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki if (mPopup.isOverflowAnimating()) { 1578cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki // Eat the touch event. 1579cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki return true; 1580cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki } 1581cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki return super.dispatchTouchEvent(ev); 1582cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki } 1583cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki 1584cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki @Override 1585cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki protected boolean awakenScrollBars() { 1586cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki return super.awakenScrollBars(); 1587cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki } 1588cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki } 1589cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki 1590cc9d617dca3e3b332db2e2e7293c5501dd935cecAbodunrinwa Toki /** 15917e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * A custom interpolator used for various floating toolbar animations. 15920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 15937e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static final class LogAccelerateInterpolator implements Interpolator { 1594517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 15957e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static final int BASE = 100; 15967e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static final float LOGS_SCALE = 1f / computeLog(1, BASE); 15977e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki 15987e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static float computeLog(float t, int base) { 15997e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return (float) (1 - Math.pow(base, -t)); 1600ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 1601517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 16027e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki @Override 16037e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public float getInterpolation(float t) { 16047e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki return 1 - computeLog(1 - t, BASE) * LOGS_SCALE; 1605f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki } 1606f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki } 1607f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki 16087e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki /** 16097e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki * A helper for generating views for the overflow panel. 16107e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki */ 16117e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static final class OverflowPanelViewHelper { 1612b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki 1613852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki private final View mCalculator; 1614852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki private final int mIconTextSpacing; 1615852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki private final int mSidePadding; 1616517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 16177e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private final Context mContext; 1618517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 161949ec54250f0cafd962c3c5f7f286875cf499483aAbodunrinwa Toki public OverflowPanelViewHelper(Context context, int iconTextSpacing) { 16207e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki mContext = Preconditions.checkNotNull(context); 162149ec54250f0cafd962c3c5f7f286875cf499483aAbodunrinwa Toki mIconTextSpacing = iconTextSpacing; 1622852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki mSidePadding = context.getResources() 1623852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_overflow_side_padding); 1624852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki mCalculator = createMenuButton(null); 16257e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 1626517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 16277e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki public View getView(MenuItem menuItem, int minimumWidth, View convertView) { 16287e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki Preconditions.checkNotNull(menuItem); 1629852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki if (convertView != null) { 16309c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki updateMenuItemButton( 16319c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki convertView, menuItem, mIconTextSpacing, shouldShowIcon(menuItem)); 16327e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } else { 1633852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki convertView = createMenuButton(menuItem); 16347e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 1635852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki convertView.setMinimumWidth(minimumWidth); 1636852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki return convertView; 1637517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1638517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1639852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki public int calculateWidth(MenuItem menuItem) { 16409c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki updateMenuItemButton( 16419c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki mCalculator, menuItem, mIconTextSpacing, shouldShowIcon(menuItem)); 1642852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki mCalculator.measure( 1643852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); 1644852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki return mCalculator.getMeasuredWidth(); 1645517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1646b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki 1647852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki private View createMenuButton(MenuItem menuItem) { 16489c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki View button = createMenuItemButton( 16499c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki mContext, menuItem, mIconTextSpacing, shouldShowIcon(menuItem)); 1650852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki button.setPadding(mSidePadding, 0, mSidePadding, 0); 1651852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki return button; 16527e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki } 16539c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki 16549c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki private boolean shouldShowIcon(MenuItem menuItem) { 16559c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki if (menuItem != null) { 16569c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki return menuItem.getGroupId() == android.R.id.textAssist; 16579c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki } 16589c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki return false; 16599c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki } 1660b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki } 1661517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1662517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1663b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki /** 1664852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki * Creates and returns a menu button for the specified menu item. 1665b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki */ 1666852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki private static View createMenuItemButton( 16679c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki Context context, MenuItem menuItem, int iconTextSpacing, boolean showIcon) { 1668852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki final View menuItemButton = LayoutInflater.from(context) 1669852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki .inflate(R.layout.floating_popup_menu_button, null); 1670852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki if (menuItem != null) { 16719c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki updateMenuItemButton(menuItemButton, menuItem, iconTextSpacing, showIcon); 1672b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1673852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki return menuItemButton; 1674b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1675517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1676517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1677852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki * Updates the specified menu item button with the specified menu item data. 1678517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1679852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki private static void updateMenuItemButton( 16809c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki View menuItemButton, MenuItem menuItem, int iconTextSpacing, boolean showIcon) { 16819c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki final TextView buttonText = menuItemButton.findViewById( 1682852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki R.id.floating_toolbar_menu_item_text); 16839c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki buttonText.setEllipsize(null); 1684852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki if (TextUtils.isEmpty(menuItem.getTitle())) { 1685852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki buttonText.setVisibility(View.GONE); 1686852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki } else { 1687852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki buttonText.setVisibility(View.VISIBLE); 1688852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki buttonText.setText(menuItem.getTitle()); 1689852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki } 16909c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki final ImageView buttonIcon = menuItemButton.findViewById( 16919c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki R.id.floating_toolbar_menu_item_image); 16929c881f227b2a136193a0a9236100075363a76f68Abodunrinwa Toki if (menuItem.getIcon() == null || !showIcon) { 1693852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki buttonIcon.setVisibility(View.GONE); 1694852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki if (buttonText != null) { 1695852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki buttonText.setPaddingRelative(0, 0, 0, 0); 16967039cbc6f3a596aee6851014019849490f358f13Vladislav Kaznacheev } 16977039cbc6f3a596aee6851014019849490f358f13Vladislav Kaznacheev } else { 1698852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki buttonIcon.setVisibility(View.VISIBLE); 1699852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki buttonIcon.setImageDrawable(menuItem.getIcon()); 1700852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki if (buttonText != null) { 1701852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki buttonText.setPaddingRelative(iconTextSpacing, 0, 0, 0); 1702852e9ac797f5bde6442a1ddeb1f5bf25381b0816Abodunrinwa Toki } 17037039cbc6f3a596aee6851014019849490f358f13Vladislav Kaznacheev } 17047039cbc6f3a596aee6851014019849490f358f13Vladislav Kaznacheev final CharSequence contentDescription = menuItem.getContentDescription(); 17057039cbc6f3a596aee6851014019849490f358f13Vladislav Kaznacheev if (TextUtils.isEmpty(contentDescription)) { 17067039cbc6f3a596aee6851014019849490f358f13Vladislav Kaznacheev menuItemButton.setContentDescription(menuItem.getTitle()); 17077039cbc6f3a596aee6851014019849490f358f13Vladislav Kaznacheev } else { 17087039cbc6f3a596aee6851014019849490f358f13Vladislav Kaznacheev menuItemButton.setContentDescription(contentDescription); 1709b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1710517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1711517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1712517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static ViewGroup createContentContainer(Context context) { 17138a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context) 1714517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki .inflate(R.layout.floating_popup_container, null); 17156be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki contentContainer.setLayoutParams(new ViewGroup.LayoutParams( 17166be228c1116aac14143b2f1420f08f990d0ccd45Abodunrinwa Toki ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 17178a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki contentContainer.setTag(FLOATING_TOOLBAR_TAG); 171817f91d5413d53674aefb8995bdbbb41cdc0c8811Mihai Popa contentContainer.setClipToOutline(true); 17198a5e1ae2f4e1aaf2db2a217e841371e18851df3fAbodunrinwa Toki return contentContainer; 1720517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1721517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 17227e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki private static PopupWindow createPopupWindow(ViewGroup content) { 1723517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup popupContentHolder = new LinearLayout(content.getContext()); 1724517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki PopupWindow popupWindow = new PopupWindow(popupContentHolder); 1725bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // TODO: Use .setLayoutInScreenEnabled(true) instead of .setClippingEnabled(false) 1726bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // unless FLAG_LAYOUT_IN_SCREEN has any unintentional side-effects. 1727bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa popupWindow.setClippingEnabled(false); 1728103d48ec09cbaeedf28b66425cde9198f767e0d5Abodunrinwa Toki popupWindow.setWindowLayoutType( 1729103d48ec09cbaeedf28b66425cde9198f767e0d5Abodunrinwa Toki WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL); 1730517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki popupWindow.setAnimationStyle(0); 1731517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 1732517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki content.setLayoutParams(new ViewGroup.LayoutParams( 1733517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 1734517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki popupContentHolder.addView(content); 1735517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return popupWindow; 1736517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1737517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1738517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 17397aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki * Creates an "appear" animation for the specified view. 1740517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 1741517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param view The view to animate 1742517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 17437aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki private static AnimatorSet createEnterAnimation(View view) { 17447e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki AnimatorSet animation = new AnimatorSet(); 17457aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki animation.playTogether( 17467e29d1b4fc77e3866dec1bc75f45055c70539ed6Abodunrinwa Toki ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150)); 17477aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki return animation; 1748517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1749517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1750517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 17517aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki * Creates a "disappear" animation for the specified view. 1752517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 1753517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param view The view to animate 1754cdffaa4c5af71b4bd0c99a98d411ee3883ec4733Abodunrinwa Toki * @param startDelay The start delay of the animation 1755517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param listener The animation listener 1756517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 17577aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki private static AnimatorSet createExitAnimation( 1758cdffaa4c5af71b4bd0c99a98d411ee3883ec4733Abodunrinwa Toki View view, int startDelay, Animator.AnimatorListener listener) { 17597aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki AnimatorSet animation = new AnimatorSet(); 17607aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki animation.playTogether( 1761b9acbe40d298612a2ab6bfb15842e63ff8f09af5Abodunrinwa Toki ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100)); 17627aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki animation.setStartDelay(startDelay); 17637aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki animation.addListener(listener); 17647aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki return animation; 1765517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1766517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1767079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki /** 1768079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki * Returns a re-themed context with controlled look and feel for views. 1769079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki */ 1770079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki private static Context applyDefaultTheme(Context originalContext) { 1771079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki TypedArray a = originalContext.obtainStyledAttributes(new int[]{R.attr.isLightTheme}); 1772079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki boolean isLightTheme = a.getBoolean(0, true); 1773fb4b6b8fd26a9dc9081d7a864e6d6ba609988975Mihai Popa int themeId 1774fb4b6b8fd26a9dc9081d7a864e6d6ba609988975Mihai Popa = isLightTheme ? R.style.Theme_DeviceDefault_Light : R.style.Theme_DeviceDefault; 1775079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki a.recycle(); 1776079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki return new ContextThemeWrapper(originalContext, themeId); 1777079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki } 177830f8ef46e5c02b3680a9e355690d74a73718ced8Abodunrinwa Toki} 1779