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; 236bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarriimport android.content.ComponentCallbacks; 240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.content.Context; 256bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarriimport android.content.res.Configuration; 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; 310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.graphics.drawable.ColorDrawable; 32b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Tokiimport android.text.TextUtils; 33517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.util.Size; 34079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Tokiimport android.view.ContextThemeWrapper; 350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Gravity; 360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.LayoutInflater; 370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Menu; 380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.MenuItem; 390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.View; 400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.View.MeasureSpec; 410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.ViewGroup; 42517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.ViewTreeObserver; 430c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Window; 44517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.WindowManager; 45517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.Animation; 46517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.AnimationSet; 47517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.Transformation; 48517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.AdapterView; 49517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.ArrayAdapter; 500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.Button; 510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.ImageButton; 52b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Tokiimport android.widget.ImageView; 530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.LinearLayout; 54517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.ListView; 550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.PopupWindow; 56517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.TextView; 570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.ArrayList; 590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.LinkedList; 600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.List; 610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 62517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport com.android.internal.R; 63517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport com.android.internal.util.Preconditions; 64517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 650c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki/** 660c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * A floating toolbar for showing contextual menu items. 670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * This view shows as many menu item buttons as can fit in the horizontal toolbar and the 680c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * the remaining menu items in a vertical overflow view when the overflow button is clicked. 690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The horizontal toolbar morphs into the vertical overflow view. 700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 710c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokipublic final class FloatingToolbar { 720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 73517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki // This class is responsible for the public API of the floating toolbar. 74517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki // It delegates rendering operations to the FloatingToolbarPopup. 75517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER = 770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki new MenuItem.OnMenuItemClickListener() { 780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki @Override 790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public boolean onMenuItemClick(MenuItem item) { 800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return false; 810c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 820c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki }; 830c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 840c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private final Context mContext; 850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private final FloatingToolbarPopup mPopup; 860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 870c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private final Rect mContentRect = new Rect(); 88c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki private final Rect mPreviousContentRect = new Rect(); 890c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 900c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private Menu mMenu; 915047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki private List<Object> mShowingMenuItems = new ArrayList<Object>(); 920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER; 930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 940c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private int mSuggestedWidth; 95517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private boolean mWidthChanged = true; 960c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 976bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri private final ComponentCallbacks mOrientationChangeHandler = new ComponentCallbacks() { 986bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri @Override 996bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri public void onConfigurationChanged(Configuration newConfig) { 1006bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri if (mPopup.isShowing() && mPopup.viewPortHasChanged()) { 1016bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri mWidthChanged = true; 1026bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri updateLayout(); 1036bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri } 1046bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri } 1056bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri 1066bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri @Override 1076bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri public void onLowMemory() {} 1086bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri }; 1096bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri 1100c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1110c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Initializes a floating toolbar. 1120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1130c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar(Context context, Window window) { 114079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki Preconditions.checkNotNull(context); 115079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki Preconditions.checkNotNull(window); 116079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki mContext = applyDefaultTheme(context); 117079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki mPopup = new FloatingToolbarPopup(mContext, window.getDecorView()); 1180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Sets the menu to be shown in this floating toolbar. 1220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the 1230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * toolbar. 1240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar setMenu(Menu menu) { 1260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mMenu = Preconditions.checkNotNull(menu); 1270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 1280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1317270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Sets the custom listener for invocation of menu items in this floating toolbar. 1320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar setOnMenuItemClickListener( 1340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki MenuItem.OnMenuItemClickListener menuItemClickListener) { 1350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (menuItemClickListener != null) { 1360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mMenuItemClickListener = menuItemClickListener; 1370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } else { 1380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER; 1390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 1410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1420c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1430c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1440c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Sets the content rectangle. This is the area of the interesting content that this toolbar 1450c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * should avoid obstructing. 1460c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the 1470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * toolbar. 1480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar setContentRect(Rect rect) { 1500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mContentRect.set(Preconditions.checkNotNull(rect)); 1510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 1520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Sets the suggested width of this floating toolbar. 1560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The actual width will be about this size but there are no guarantees that it will be exactly 1570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * the suggested width. 1580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the 1590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * toolbar. 1600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar setSuggestedWidth(int suggestedWidth) { 162517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki // Check if there's been a substantial width spec change. 163517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int difference = Math.abs(suggestedWidth - mSuggestedWidth); 164517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mWidthChanged = difference > (mSuggestedWidth * 0.2); 165517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1660c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mSuggestedWidth = suggestedWidth; 1670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 1680c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1710c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Shows this floating toolbar. 1720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar show() { 1746bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri mContext.unregisterComponentCallbacks(mOrientationChangeHandler); 1756bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri mContext.registerComponentCallbacks(mOrientationChangeHandler); 1760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu); 177517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (!isCurrentlyShowing(menuItems) || mWidthChanged) { 1780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mPopup.dismiss(); 179517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth); 1805047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki mShowingMenuItems = getShowingMenuItemsReferences(menuItems); 1810c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1820c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (!mPopup.isShowing()) { 183ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki mPopup.show(mContentRect); 184c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki } else if (!mPreviousContentRect.equals(mContentRect)) { 185c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki mPopup.updateCoordinates(mContentRect); 1860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 187517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mWidthChanged = false; 188c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki mPreviousContentRect.set(mContentRect); 1890c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 1900c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1910c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Updates this floating toolbar to reflect recent position and view updates. 1940c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * NOTE: This method is a no-op if the toolbar isn't showing. 1950c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1960c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public FloatingToolbar updateLayout() { 1970c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (mPopup.isShowing()) { 1980c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki // show() performs all the logic we need here. 1990c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki show(); 2000c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2010c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return this; 2020c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2030c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2040c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 2050c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Dismisses this floating toolbar. 2060c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 2070c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public void dismiss() { 2086bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri mContext.unregisterComponentCallbacks(mOrientationChangeHandler); 2090c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mPopup.dismiss(); 2100c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2110c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 2137270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Hides this floating toolbar. This is a no-op if the toolbar is not showing. 2147270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Use {@link #isHidden()} to distinguish between a hidden and a dismissed toolbar. 2157270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 2167270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public void hide() { 2177270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mPopup.hide(); 2187270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 2197270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 2207270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 2217270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Returns {@code true} if this toolbar is currently showing. {@code false} otherwise. 2220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 2230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public boolean isShowing() { 2240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return mPopup.isShowing(); 2250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 2287270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Returns {@code true} if this toolbar is currently hidden. {@code false} otherwise. 2297270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 2307270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public boolean isHidden() { 2317270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki return mPopup.isHidden(); 2327270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 2337270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 2347270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 235517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Returns true if this floating toolbar is currently showing the specified menu items. 2360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 237517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private boolean isCurrentlyShowing(List<MenuItem> menuItems) { 2385047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki return mShowingMenuItems.equals(getShowingMenuItemsReferences(menuItems)); 2390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 2420c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Returns the visible and enabled menu items in the specified menu. 2430c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * This method is recursive. 2440c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 2450c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki private List<MenuItem> getVisibleAndEnabledMenuItems(Menu menu) { 2460c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki List<MenuItem> menuItems = new ArrayList<MenuItem>(); 2470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki for (int i = 0; (menu != null) && (i < menu.size()); i++) { 2480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki MenuItem menuItem = menu.getItem(i); 2490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (menuItem.isVisible() && menuItem.isEnabled()) { 2500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki Menu subMenu = menuItem.getSubMenu(); 2510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (subMenu != null) { 2520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki menuItems.addAll(getVisibleAndEnabledMenuItems(subMenu)); 2530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } else { 2540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki menuItems.add(menuItem); 2550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return menuItems; 2590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2615047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki private List<Object> getShowingMenuItemsReferences(List<MenuItem> menuItems) { 2625047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki List<Object> references = new ArrayList<Object>(); 2630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki for (MenuItem menuItem : menuItems) { 2645047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki if (isIconOnlyMenuItem(menuItem)) { 2655047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki references.add(menuItem.getIcon()); 2665047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki } else { 2675047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki references.add(menuItem.getTitle()); 2685047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki } 2690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2705047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki return references; 2710c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 2720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 2740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 275517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * A popup window used by the floating toolbar. 276517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 277517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * This class is responsible for the rendering/animation of the floating toolbar. 278517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * It can hold one of 2 panels (i.e. main panel and overflow panel) at a time. 279517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * It delegates specific panel functionality to the appropriate panel. 2800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 281517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static final class FloatingToolbarPopup { 2820c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 283517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public static final int OVERFLOW_DIRECTION_UP = 0; 284517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public static final int OVERFLOW_DIRECTION_DOWN = 1; 2850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 286079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki private final Context mContext; 287517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final View mParent; 288517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final PopupWindow mPopupWindow; 289517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final ViewGroup mContentContainer; 290f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki private final int mMarginHorizontal; 291f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki private final int mMarginVertical; 2920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 293517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final Animation.AnimationListener mOnOverflowOpened = 294517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki new Animation.AnimationListener() { 295517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 296517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onAnimationStart(Animation animation) {} 2970c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 298517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 299517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onAnimationEnd(Animation animation) { 300b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki setOverflowPanelAsContent(); 301517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOverflowPanel.fadeIn(true); 302517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 3030c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 304517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 305517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onAnimationRepeat(Animation animation) {} 306517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 307517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final Animation.AnimationListener mOnOverflowClosed = 308517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki new Animation.AnimationListener() { 309517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 310517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onAnimationStart(Animation animation) {} 3110c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 312517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 313517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onAnimationEnd(Animation animation) { 314b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki setMainPanelAsContent(); 315517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mMainPanel.fadeIn(true); 316517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 3170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 3180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki @Override 319517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onAnimationRepeat(Animation animation) { 3200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 3210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki }; 3227270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private final AnimatorSet mDismissAnimation; 3237270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private final AnimatorSet mHideAnimation; 324c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki private final AnimationSet mOpenOverflowAnimation = new AnimationSet(true); 325c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki private final AnimationSet mCloseOverflowAnimation = new AnimationSet(true); 3260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 327517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final Runnable mOpenOverflow = new Runnable() { 328517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 329517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void run() { 330517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki openOverflow(); 331517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 332517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 333517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final Runnable mCloseOverflow = new Runnable() { 334517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 335517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void run() { 336517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki closeOverflow(); 337517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 338517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 339517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 340bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa private final Rect mViewPortOnScreen = new Rect(); 3414b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa private final Point mCoordsOnWindow = new Point(); 3424b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa private final int[] mTmpCoords = new int[2]; 3436bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri private final Rect mTmpRect = new Rect(); 344ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 345517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final Region mTouchableRegion = new Region(); 346d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = 347d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki new ViewTreeObserver.OnComputeInternalInsetsListener() { 348d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki public void onComputeInternalInsets( 349d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki ViewTreeObserver.InternalInsetsInfo info) { 350d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki info.contentInsets.setEmpty(); 351d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki info.visibleInsets.setEmpty(); 352d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki info.touchableRegion.set(mTouchableRegion); 353d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo 354d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki .TOUCHABLE_INSETS_REGION); 355d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki } 356d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki }; 357517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 3587270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private boolean mDismissed = true; // tracks whether this popup is dismissed or dismissing. 3597270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private boolean mHidden; // tracks whether this popup is hidden or hiding. 3600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 361517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private FloatingToolbarOverflowPanel mOverflowPanel; 362517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private FloatingToolbarMainPanel mMainPanel; 363517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private int mOverflowDirection; 364517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 3650c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 366517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Initializes a new floating toolbar popup. 3670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * 368517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param parent A parent view to get the {@link android.view.View#getWindowToken()} token 369517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * from. 3700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 371079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki public FloatingToolbarPopup(Context context, View parent) { 3720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mParent = Preconditions.checkNotNull(parent); 373079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki mContext = Preconditions.checkNotNull(context); 374079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki mContentContainer = createContentContainer(context); 3750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki mPopupWindow = createPopupWindow(mContentContainer); 3767aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki mDismissAnimation = createExitAnimation( 377517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer, 3784ce050bd83b8c311d7cf7b50e0a36a28df68bc4aAbodunrinwa Toki 150, // startDelay 379517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki new AnimatorListenerAdapter() { 380517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 381517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onAnimationEnd(Animator animation) { 382517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mPopupWindow.dismiss(); 383b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.removeAllViews(); 384517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 385517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }); 3867aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki mHideAnimation = createExitAnimation( 3877270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mContentContainer, 3884ce050bd83b8c311d7cf7b50e0a36a28df68bc4aAbodunrinwa Toki 0, // startDelay 3897270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki new AnimatorListenerAdapter() { 3907270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki @Override 3917270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public void onAnimationEnd(Animator animation) { 3927270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mPopupWindow.dismiss(); 3937270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 3947270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki }); 3956cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki mMarginHorizontal = parent.getResources() 3966cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); 3976cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki mMarginVertical = parent.getResources() 3986cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin); 399517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 400517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 401517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 402517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Lays out buttons for the specified menu items. 403517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 4046c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki public void layoutMenuItems( 4056c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki List<MenuItem> menuItems, 4066c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki MenuItem.OnMenuItemClickListener menuItemClickListener, 4076c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki int suggestedWidth) { 408ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki Preconditions.checkNotNull(menuItems); 409ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 410517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.removeAllViews(); 411517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (mMainPanel == null) { 412079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki mMainPanel = new FloatingToolbarMainPanel(mContext, mOpenOverflow); 413517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 414517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki List<MenuItem> overflowMenuItems = 415e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki mMainPanel.layoutMenuItems(menuItems, getToolbarWidth(suggestedWidth)); 416517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mMainPanel.setOnMenuItemClickListener(menuItemClickListener); 417517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (!overflowMenuItems.isEmpty()) { 418517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (mOverflowPanel == null) { 419517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOverflowPanel = 420079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki new FloatingToolbarOverflowPanel(mContext, mCloseOverflow); 421517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 422517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOverflowPanel.setMenuItems(overflowMenuItems); 423517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOverflowPanel.setOnMenuItemClickListener(menuItemClickListener); 424517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 425517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki updatePopupSize(); 4260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 4270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 4280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 4290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Shows this popup at the specified coordinates. 4300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. 4310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 432bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa public void show(Rect contentRectOnScreen) { 433bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa Preconditions.checkNotNull(contentRectOnScreen); 434ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 4350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki if (isShowing()) { 4360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return; 4370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 4380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 4397270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHidden = false; 4407270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mDismissed = false; 4410ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki cancelDismissAndHideAnimations(); 4420ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki cancelOverflowAnimations(); 443ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 444b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki // Make sure a panel is set as the content. 445b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki if (mContentContainer.getChildCount() == 0) { 446b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki setMainPanelAsContent(); 447c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki // If we're yet to show the popup, set the container visibility to zero. 448c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki // The "show" animation will make this visible. 449c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki mContentContainer.setAlpha(0); 450b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki } 451bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa refreshCoordinatesAndOverflowDirection(contentRectOnScreen); 452517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki preparePopupContent(); 4534b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // We need to specify the position in window coordinates. 454bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can 455bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // specify the popup poision in screen coordinates. 4564b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x, 4574b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa mCoordsOnWindow.y); 458d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki setTouchableSurfaceInsetsComputer(); 4597270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki runShowAnimation(); 4600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 4610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 4620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 4630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op. 4640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 4650c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public void dismiss() { 4660ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki if (mDismissed) { 4670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki return; 4680c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 4690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 4707270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHidden = false; 4717270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mDismissed = true; 4720ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki mHideAnimation.cancel(); 4737270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki runDismissAnimation(); 4747270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki setZeroTouchableSurface(); 4757270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 4767270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 4777270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 4787270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Hides this popup. This is a no-op if this popup is not showing. 4797270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup. 4807270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 4817270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public void hide() { 4827270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki if (!isShowing()) { 4837270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki return; 4847270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 4857270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 4867270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHidden = true; 4877270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki runHideAnimation(); 488517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki setZeroTouchableSurface(); 4890c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 4900c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 4910c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 4920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Returns {@code true} if this popup is currently showing. {@code false} otherwise. 4930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 4940c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public boolean isShowing() { 495c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki return !mDismissed && !mHidden; 4967270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 4977270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 4987270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 4997270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Returns {@code true} if this popup is currently hidden. {@code false} otherwise. 5007270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 5017270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki public boolean isHidden() { 5027270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki return mHidden; 5030c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 5040c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 5050c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 5060c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Updates the coordinates of this popup. 5070c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The specified coordinates may be adjusted to make sure the popup is entirely on-screen. 5087270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * This is a no-op if this popup is not showing. 5090c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 510bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa public void updateCoordinates(Rect contentRectOnScreen) { 511bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa Preconditions.checkNotNull(contentRectOnScreen); 512ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 513c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki if (!isShowing() || !mPopupWindow.isShowing()) { 514517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return; 5150c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 516517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 5170ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki cancelOverflowAnimations(); 518bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa refreshCoordinatesAndOverflowDirection(contentRectOnScreen); 519517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki preparePopupContent(); 5204b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // We need to specify the position in window coordinates. 521bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can 522bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // specify the popup poision in screen coordinates. 5234b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa mPopupWindow.update(mCoordsOnWindow.x, mCoordsOnWindow.y, getWidth(), getHeight()); 5240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 5250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 5260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 5270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Returns the width of this popup. 5280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 5290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public int getWidth() { 530517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return mPopupWindow.getWidth(); 5310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 5320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 5330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 5340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Returns the height of this popup. 5350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 5360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public int getHeight() { 537517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return mPopupWindow.getHeight(); 5380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 5390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 5400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 5410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * Returns the context this popup is running in. 5420c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 5430c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki public Context getContext() { 544079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki return mContext; 5450c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 5460c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 547bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa private void refreshCoordinatesAndOverflowDirection(Rect contentRectOnScreen) { 5486d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki refreshViewPort(); 549e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki 550bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa int x = contentRectOnScreen.centerX() - getWidth() / 2; 551e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki // Update x so that the toolbar isn't rendered behind the nav bar in landscape. 552bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa x = Math.max(0, Math.min(x, mViewPortOnScreen.right - getWidth())); 553e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki 5546d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki int y; 5559ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki 556bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa int availableHeightAboveContent = contentRectOnScreen.top - mViewPortOnScreen.top; 557bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa int availableHeightBelowContent = mViewPortOnScreen.bottom - contentRectOnScreen.bottom; 5589ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki 5596d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki if (mOverflowPanel == null) { // There is no overflow. 5609ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin()) { 5616d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the top of the content. 562bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin(); 5639ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin()) { 5646d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the bottom of the content. 565bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.bottom; 566079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki } else if (availableHeightBelowContent >= getEstimatedToolbarHeight(mContext)) { 5679ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // Just enough space to fit the toolbar with no vertical margins. 568bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.bottom - mMarginVertical; 5696d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } else { 5706d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Not enough space. Prefer to position as high as possible. 5716d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki y = Math.max( 572bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa mViewPortOnScreen.top, 573bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa contentRectOnScreen.top - getToolbarHeightWithVerticalMargin()); 5746d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } 5756d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } else { // There is an overflow. 5769ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki int margin = 2 * mMarginVertical; 5779ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki int minimumOverflowHeightWithMargin = mOverflowPanel.getMinimumHeight() + margin; 578bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa int availableHeightThroughContentDown = mViewPortOnScreen.bottom - 579bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa contentRectOnScreen.top + getToolbarHeightWithVerticalMargin(); 580bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa int availableHeightThroughContentUp = contentRectOnScreen.bottom - 581bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa mViewPortOnScreen.top + getToolbarHeightWithVerticalMargin(); 5829ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki 5839ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki if (availableHeightAboveContent >= minimumOverflowHeightWithMargin) { 5846d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the top of the content rect for the overflow. 5856d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Position above and open upwards. 5869ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki updateOverflowHeight(availableHeightAboveContent - margin); 587bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.top - getHeight(); 5886d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki mOverflowDirection = OVERFLOW_DIRECTION_UP; 5899ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki } else if (availableHeightAboveContent >= getToolbarHeightWithVerticalMargin() 5909ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki && availableHeightThroughContentDown >= minimumOverflowHeightWithMargin) { 5916d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the top of the content rect for the main panel 5926d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // but not the overflow. 5936d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Position above but open downwards. 5949ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki updateOverflowHeight(availableHeightThroughContentDown - margin); 595bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.top - getToolbarHeightWithVerticalMargin(); 5966d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki mOverflowDirection = OVERFLOW_DIRECTION_DOWN; 5979ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki } else if (availableHeightBelowContent >= minimumOverflowHeightWithMargin) { 5986d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // There is enough space at the bottom of the content rect for the overflow. 5996d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Position below and open downwards. 6009ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki updateOverflowHeight(availableHeightBelowContent - margin); 601bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.bottom; 6026d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki mOverflowDirection = OVERFLOW_DIRECTION_DOWN; 6039ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki } else if (availableHeightBelowContent >= getToolbarHeightWithVerticalMargin() 604bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa && mViewPortOnScreen.height() >= minimumOverflowHeightWithMargin) { 6059ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // There is enough space at the bottom of the content rect for the main panel 6069ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // but not the overflow. 6079ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // Position below but open upwards. 6089ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki updateOverflowHeight(availableHeightThroughContentUp - margin); 609bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = contentRectOnScreen.bottom + getToolbarHeightWithVerticalMargin() - 610bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa getHeight(); 6119ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki mOverflowDirection = OVERFLOW_DIRECTION_UP; 6126d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } else { 6136d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Not enough space. 6149ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki // Position at the top of the view port and open downwards. 615bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa updateOverflowHeight(mViewPortOnScreen.height() - margin); 616bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa y = mViewPortOnScreen.top; 6179ae95dff1d9dc78ad98b85fbdb79108dd8a09957Abodunrinwa Toki mOverflowDirection = OVERFLOW_DIRECTION_DOWN; 6186d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } 619ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki mOverflowPanel.setOverflowDirection(mOverflowDirection); 620ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 6216d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki 6224b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // We later specify the location of PopupWindow relative to the attached window. 6234b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // The idea here is that 1) we can get the location of a View in both window coordinates 6244b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // and screen coordiantes, where the offset between them should be equal to the window 6254b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // origin, and 2) we can use an arbitrary for this calculation while calculating the 6264b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // location of the rootview is supposed to be least expensive. 6274b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can avoid 6284b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa // the following calculation. 6294b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa mParent.getRootView().getLocationOnScreen(mTmpCoords); 6304b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int rootViewLeftOnScreen = mTmpCoords[0]; 6314b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int rootViewTopOnScreen = mTmpCoords[1]; 6324b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa mParent.getRootView().getLocationInWindow(mTmpCoords); 6334b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int rootViewLeftOnWindow = mTmpCoords[0]; 6344b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int rootViewTopOnWindow = mTmpCoords[1]; 6354b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int windowLeftOnScreen = rootViewLeftOnScreen - rootViewLeftOnWindow; 6364b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa int windowTopOnScreen = rootViewTopOnScreen - rootViewTopOnWindow; 6374b26997eeb6bbb526738bcbfaaa9b7147ba0f4a2Yohei Yukawa mCoordsOnWindow.set(x - windowLeftOnScreen, y - windowTopOnScreen); 638ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 639ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 640ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki private int getToolbarHeightWithVerticalMargin() { 641079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki return getEstimatedToolbarHeight(mContext) + mMarginVertical * 2; 642f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki } 643f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki 6440c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 6457270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Performs the "show" animation on the floating popup. 6467270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki */ 6477270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private void runShowAnimation() { 6487aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki createEnterAnimation(mContentContainer).start(); 6497270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki } 6507270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki 6517270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki /** 6527270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Performs the "dismiss" animation on the floating popup. 6530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 6547270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private void runDismissAnimation() { 6557270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mDismissAnimation.start(); 6560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 6570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 6580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 6597270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki * Performs the "hide" animation on the floating popup. 6600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 6617270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki private void runHideAnimation() { 6627270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHideAnimation.start(); 6630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 6640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 6650ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki private void cancelDismissAndHideAnimations() { 6667270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mDismissAnimation.cancel(); 6677270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki mHideAnimation.cancel(); 6680ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki } 6690ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki 6700ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki private void cancelOverflowAnimations() { 671c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki if (mOpenOverflowAnimation.hasStarted() 672c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki && !mOpenOverflowAnimation.hasEnded()) { 673c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki // Remove the animation listener, stop the animation, 674c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki // then trigger the lister explicitly so it is not posted 675c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki // to the message queue. 676c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki mOpenOverflowAnimation.setAnimationListener(null); 677c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki mContentContainer.clearAnimation(); 678c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki mOnOverflowOpened.onAnimationEnd(null); 679c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki } 680c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki if (mCloseOverflowAnimation.hasStarted() 681c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki && !mCloseOverflowAnimation.hasEnded()) { 682c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki // Remove the animation listener, stop the animation, 683c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki // then trigger the lister explicitly so it is not posted 684c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki // to the message queue. 685c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki mCloseOverflowAnimation.setAnimationListener(null); 686c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki mContentContainer.clearAnimation(); 687c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki mOnOverflowClosed.onAnimationEnd(null); 688c107b0ecdcd4e2f89ae4bec818c3a94f45c3c15eAbodunrinwa Toki } 689517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 690517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 691517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 692517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Opens the floating toolbar overflow. 693517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * This method should not be called if menu items have not been laid out with 694b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}. 695517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 696517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @throws IllegalStateException if called when menu items have not been laid out. 697517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 698517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void openOverflow() { 699b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki Preconditions.checkState(mMainPanel != null); 700b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki Preconditions.checkState(mOverflowPanel != null); 701517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 702517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mMainPanel.fadeOut(true); 703517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Size overflowPanelSize = mOverflowPanel.measure(); 704f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki final int targetWidth = overflowPanelSize.getWidth(); 705517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int targetHeight = overflowPanelSize.getHeight(); 706517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final boolean morphUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP); 707517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int startWidth = mContentContainer.getWidth(); 708517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int startHeight = mContentContainer.getHeight(); 709517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final float startY = mContentContainer.getY(); 7106c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki final float left = mContentContainer.getX(); 7116c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki final float right = left + mContentContainer.getWidth(); 712517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Animation widthAnimation = new Animation() { 713517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 714517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 715517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams params = mContentContainer.getLayoutParams(); 716517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); 717517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki params.width = startWidth + deltaWidth; 718517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.setLayoutParams(params); 7196cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki if (isRTL()) { 7206c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki mContentContainer.setX(left); 7216c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki } else { 7226c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki mContentContainer.setX(right - mContentContainer.getWidth()); 7236c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki } 724517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 725517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 726517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Animation heightAnimation = new Animation() { 727517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 728517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 729517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams params = mContentContainer.getLayoutParams(); 730517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight)); 731517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki params.height = startHeight + deltaHeight; 732517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.setLayoutParams(params); 733517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (morphUpwards) { 734517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki float y = startY - (mContentContainer.getHeight() - startHeight); 735517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.setY(y); 736517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 737517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 738517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 739517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki widthAnimation.setDuration(240); 740517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki heightAnimation.setDuration(180); 741517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki heightAnimation.setStartOffset(60); 742b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mOpenOverflowAnimation.getAnimations().clear(); 743b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mOpenOverflowAnimation.setAnimationListener(mOnOverflowOpened); 744b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mOpenOverflowAnimation.addAnimation(widthAnimation); 745b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mOpenOverflowAnimation.addAnimation(heightAnimation); 746b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.startAnimation(mOpenOverflowAnimation); 747517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 748517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 749517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 750517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Opens the floating toolbar overflow. 751517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * This method should not be called if menu items have not been laid out with 752517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}. 753517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 754b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki * @throws IllegalStateException if called when menu items have not been laid out. 755517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 756517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void closeOverflow() { 757b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki Preconditions.checkState(mMainPanel != null); 758b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki Preconditions.checkState(mOverflowPanel != null); 759517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 760517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOverflowPanel.fadeOut(true); 761517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Size mainPanelSize = mMainPanel.measure(); 762517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int targetWidth = mainPanelSize.getWidth(); 763517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int targetHeight = mainPanelSize.getHeight(); 764517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int startWidth = mContentContainer.getWidth(); 765517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final int startHeight = mContentContainer.getHeight(); 766517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final float bottom = mContentContainer.getY() + mContentContainer.getHeight(); 767517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final boolean morphedUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP); 7686c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki final float left = mContentContainer.getX(); 7696c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki final float right = left + mContentContainer.getWidth(); 770517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Animation widthAnimation = new Animation() { 771517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 772517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 773517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams params = mContentContainer.getLayoutParams(); 774517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth)); 775517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki params.width = startWidth + deltaWidth; 776517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.setLayoutParams(params); 7776cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki if (isRTL()) { 7786c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki mContentContainer.setX(left); 7796c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki } else { 7806c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki mContentContainer.setX(right - mContentContainer.getWidth()); 7816c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki } 782517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 783517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 784517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Animation heightAnimation = new Animation() { 785517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 786517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki protected void applyTransformation(float interpolatedTime, Transformation t) { 787517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams params = mContentContainer.getLayoutParams(); 788517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight)); 789517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki params.height = startHeight + deltaHeight; 790517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.setLayoutParams(params); 791517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (morphedUpwards) { 792517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.setY(bottom - mContentContainer.getHeight()); 793517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 794517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 795517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 796517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki widthAnimation.setDuration(150); 797517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki widthAnimation.setStartOffset(150); 798517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki heightAnimation.setDuration(210); 799b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mCloseOverflowAnimation.getAnimations().clear(); 800b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mCloseOverflowAnimation.setAnimationListener(mOnOverflowClosed); 801b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mCloseOverflowAnimation.addAnimation(widthAnimation); 802b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mCloseOverflowAnimation.addAnimation(heightAnimation); 803b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.startAnimation(mCloseOverflowAnimation); 804517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 805517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 806517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 807517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Prepares the content container for show and update calls. 808517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 809517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void preparePopupContent() { 810b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki // Reset visibility. 811b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki if (mMainPanel != null) { 812b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mMainPanel.fadeIn(false); 813517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 814517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (mOverflowPanel != null) { 815517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOverflowPanel.fadeIn(false); 816517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 817517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 818b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki // Reset position. 819ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki if (isMainPanelContent()) { 820b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki positionMainPanel(); 821517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 822ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki if (isOverflowPanelContent()) { 823b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki positionOverflowPanel(); 824517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 825517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 826517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 827ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki private boolean isMainPanelContent() { 828ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki return mMainPanel != null 829ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki && mContentContainer.getChildAt(0) == mMainPanel.getView(); 830ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 831ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 832ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki private boolean isOverflowPanelContent() { 833ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki return mOverflowPanel != null 834ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki && mContentContainer.getChildAt(0) == mOverflowPanel.getView(); 835ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 836ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 837517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 838517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Sets the current content to be the main view panel. 839517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 840517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void setMainPanelAsContent() { 841b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki // This should never be called if the main panel has not been initialized. 842b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki Preconditions.checkNotNull(mMainPanel); 843517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.removeAllViews(); 844517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Size mainPanelSize = mMainPanel.measure(); 845517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams params = mContentContainer.getLayoutParams(); 846517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki params.width = mainPanelSize.getWidth(); 847517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki params.height = mainPanelSize.getHeight(); 848517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.setLayoutParams(params); 849517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.addView(mMainPanel.getView()); 850b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki setContentAreaAsTouchableSurface(); 851b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki } 852b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki 853b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki /** 854b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki * Sets the current content to be the overflow view panel. 855b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki */ 856b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki private void setOverflowPanelAsContent() { 857b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki // This should never be called if the overflow panel has not been initialized. 858b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki Preconditions.checkNotNull(mOverflowPanel); 859b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.removeAllViews(); 860b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki Size overflowPanelSize = mOverflowPanel.measure(); 861b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki ViewGroup.LayoutParams params = mContentContainer.getLayoutParams(); 862b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki params.width = overflowPanelSize.getWidth(); 863b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki params.height = overflowPanelSize.getHeight(); 864b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.setLayoutParams(params); 865b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.addView(mOverflowPanel.getView()); 866b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki setContentAreaAsTouchableSurface(); 867b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki } 868b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki 869b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki /** 870b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki * Places the main view panel at the appropriate resting coordinates. 871b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki */ 872b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki private void positionMainPanel() { 873b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki Preconditions.checkNotNull(mMainPanel); 8746c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki mContentContainer.setX(mMarginHorizontal); 875b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki 876b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki float y = mMarginVertical; 877b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki if (mOverflowDirection == OVERFLOW_DIRECTION_UP) { 878b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki y = getHeight() 879b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki - (mMainPanel.getView().getMeasuredHeight() + mMarginVertical); 880b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki } 881b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.setY(y); 882b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki setContentAreaAsTouchableSurface(); 883b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki } 884b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki 885b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki /** 886b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki * Places the main view panel at the appropriate resting coordinates. 887b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki */ 888b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki private void positionOverflowPanel() { 889b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki Preconditions.checkNotNull(mOverflowPanel); 8906cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki float x; 8916cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki if (isRTL()) { 8926cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki x = mMarginHorizontal; 8936cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki } else { 8946cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki x = mPopupWindow.getWidth() 895b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki - (mOverflowPanel.getView().getMeasuredWidth() + mMarginHorizontal); 8966cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki } 897b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.setX(x); 898b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mContentContainer.setY(mMarginVertical); 899b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki setContentAreaAsTouchableSurface(); 900517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 901517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 902ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki private void updateOverflowHeight(int height) { 903ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki if (mOverflowPanel != null) { 904ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki mOverflowPanel.setSuggestedHeight(height); 905ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 906ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki // Re-measure the popup and it's contents. 907ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki boolean mainPanelContent = isMainPanelContent(); 908ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki boolean overflowPanelContent = isOverflowPanelContent(); 909ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki mContentContainer.removeAllViews(); // required to update popup size. 910ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki updatePopupSize(); 911ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki // Reset the appropriate content. 912ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki if (mainPanelContent) { 913ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki setMainPanelAsContent(); 914ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 915ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki if (overflowPanelContent) { 916ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki setOverflowPanelAsContent(); 917ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 918ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 919ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 920ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 921517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void updatePopupSize() { 922517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int width = 0; 923517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int height = 0; 924517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (mMainPanel != null) { 925517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Size mainPanelSize = mMainPanel.measure(); 926517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki width = mainPanelSize.getWidth(); 927517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki height = mainPanelSize.getHeight(); 928517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 929517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (mOverflowPanel != null) { 930517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Size overflowPanelSize = mOverflowPanel.measure(); 931517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki width = Math.max(width, overflowPanelSize.getWidth()); 932517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki height = Math.max(height, overflowPanelSize.getHeight()); 933517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 934f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mPopupWindow.setWidth(width + mMarginHorizontal * 2); 935f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mPopupWindow.setHeight(height + mMarginVertical * 2); 936517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 937517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 938e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki 939e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki private void refreshViewPort() { 940bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa mParent.getWindowVisibleDisplayFrame(mViewPortOnScreen); 941e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki } 942e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki 9436bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri private boolean viewPortHasChanged() { 9446bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri mParent.getWindowVisibleDisplayFrame(mTmpRect); 945bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa return !mTmpRect.equals(mViewPortOnScreen); 9466bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri } 9476bc12244480fcdeca84080d5382d63eb2b992883Clara Bayarri 948e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki private int getToolbarWidth(int suggestedWidth) { 949e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki int width = suggestedWidth; 950e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki refreshViewPort(); 951bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa int maximumWidth = mViewPortOnScreen.width() - 2 * mParent.getResources() 952e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin); 953e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki if (width <= 0) { 954e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki width = mParent.getResources() 955e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_preferred_width); 956e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki } 957e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki return Math.min(width, maximumWidth); 958e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki } 959e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki 960517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 961517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Sets the touchable region of this popup to be zero. This means that all touch events on 962517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * this popup will go through to the surface behind it. 963517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 964517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void setZeroTouchableSurface() { 965517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mTouchableRegion.setEmpty(); 966517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 967517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 968517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 969517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Sets the touchable region of this popup to be the area occupied by its content. 970517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 971517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void setContentAreaAsTouchableSurface() { 972517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (!mPopupWindow.isShowing()) { 973517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 974517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 975517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int width = mContentContainer.getMeasuredWidth(); 976517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int height = mContentContainer.getMeasuredHeight(); 977517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mTouchableRegion.set( 978517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki (int) mContentContainer.getX(), 979517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki (int) mContentContainer.getY(), 980517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki (int) mContentContainer.getX() + width, 981517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki (int) mContentContainer.getY() + height); 982517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 983d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki 984d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki /** 985d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki * Make the touchable area of this popup be the area specified by mTouchableRegion. 986d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki * This should be called after the popup window has been dismissed (dismiss/hide) 987d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki * and is probably being re-shown with a new content root view. 988d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki */ 989d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki private void setTouchableSurfaceInsetsComputer() { 990d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki ViewTreeObserver viewTreeObserver = mPopupWindow.getContentView() 991d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki .getRootView() 992d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki .getViewTreeObserver(); 993d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki viewTreeObserver.removeOnComputeInternalInsetsListener(mInsetsComputer); 994d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer); 995d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki } 9966cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki 9976cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki private boolean isRTL() { 9986cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki return mContentContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; 9996cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki } 1000517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1001517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1002517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1003517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * A widget that holds the primary menu items in the floating toolbar. 1004517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1005517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static final class FloatingToolbarMainPanel { 1006517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1007517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final Context mContext; 1008517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final ViewGroup mContentView; 1009517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final View.OnClickListener mMenuItemButtonOnClickListener = 1010517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki new View.OnClickListener() { 1011517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 1012517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onClick(View v) { 1013517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (v.getTag() instanceof MenuItem) { 1014517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (mOnMenuItemClickListener != null) { 1015517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOnMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag()); 1016517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1017517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1018517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1019517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 1020517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final ViewFader viewFader; 1021517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final Runnable mOpenOverflow; 1022517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1023517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private View mOpenOverflowButton; 1024517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener; 1025517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1026517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1027517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Initializes a floating toolbar popup main view panel. 1028517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 1029517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param context 1030517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param openOverflow The code that opens the toolbar popup overflow. 1031517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1032517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public FloatingToolbarMainPanel(Context context, Runnable openOverflow) { 1033517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContext = Preconditions.checkNotNull(context); 1034517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView = new LinearLayout(context); 1035517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki viewFader = new ViewFader(mContentView); 1036517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOpenOverflow = Preconditions.checkNotNull(openOverflow); 1037517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1038517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 10390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1040517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Fits as many menu items in the main panel and returns a list of the menu items that 1041517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * were not fit in. 1042517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 1043517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @return The menu items that are not included in this main panel. 10440c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1045e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int width) { 1046ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki Preconditions.checkNotNull(menuItems); 1047ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 1048e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki // Reserve space for the "open overflow" button. 1049e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki final int toolbarWidth = width - getEstimatedOpenOverflowButtonWidth(mContext); 1050517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1051517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int availableWidth = toolbarWidth; 1052517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems); 1053517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1054517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.removeAllViews(); 1055517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1056517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki boolean isFirstItem = true; 1057517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki while (!remainingMenuItems.isEmpty()) { 1058517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final MenuItem menuItem = remainingMenuItems.peek(); 1059b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki View menuItemButton = createMenuItemButton(mContext, menuItem); 1060517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1061f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki // Adding additional start padding for the first button to even out button spacing. 1062517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (isFirstItem) { 1063f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki menuItemButton.setPaddingRelative( 1064f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki (int) (1.5 * menuItemButton.getPaddingStart()), 1065517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.getPaddingTop(), 1066f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki menuItemButton.getPaddingEnd(), 1067517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.getPaddingBottom()); 1068517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki isFirstItem = false; 1069517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1070517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1071f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki // Adding additional end padding for the last button to even out button spacing. 1072517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (remainingMenuItems.size() == 1) { 1073f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki menuItemButton.setPaddingRelative( 1074f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki menuItemButton.getPaddingStart(), 1075517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.getPaddingTop(), 1076f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki (int) (1.5 * menuItemButton.getPaddingEnd()), 1077517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.getPaddingBottom()); 1078517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1079517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1080517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 1081517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth); 1082517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (menuItemButtonWidth <= availableWidth) { 1083b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki setButtonTagAndClickListener(menuItemButton, menuItem); 1084517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.addView(menuItemButton); 1085517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams params = menuItemButton.getLayoutParams(); 1086517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki params.width = menuItemButtonWidth; 1087517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.setLayoutParams(params); 1088517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki availableWidth -= menuItemButtonWidth; 1089517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki remainingMenuItems.pop(); 1090517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } else { 1091517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (mOpenOverflowButton == null) { 1092b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki mOpenOverflowButton = LayoutInflater.from(mContext) 1093517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki .inflate(R.layout.floating_popup_open_overflow_button, null); 1094517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOpenOverflowButton.setOnClickListener(new View.OnClickListener() { 1095517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 1096517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onClick(View v) { 1097517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (mOpenOverflowButton != null) { 1098517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOpenOverflow.run(); 1099517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1100517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1101517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }); 1102517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1103517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.addView(mOpenOverflowButton); 1104517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki break; 1105517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1106517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1107517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return remainingMenuItems; 1108517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1109517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1110517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) { 1111517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOnMenuItemClickListener = listener; 11120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 11130c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1114517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public View getView() { 1115517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return mContentView; 11160c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 11170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1118517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void fadeIn(boolean animate) { 1119517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki viewFader.fadeIn(animate); 1120517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1121517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1122517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void fadeOut(boolean animate) { 1123517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki viewFader.fadeOut(animate); 11240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 11250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 11260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1127517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Returns how big this panel's view should be. 1128517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * This method should only be called when the view has not been attached to a parent 1129517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * otherwise it will throw an illegal state. 1130517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1131517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public Size measure() throws IllegalStateException { 1132517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Preconditions.checkState(mContentView.getParent() == null); 1133517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 1134517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight()); 1135517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1136b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki 1137b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki private void setButtonTagAndClickListener(View menuItemButton, MenuItem menuItem) { 1138b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki View button = menuItemButton; 1139b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki if (isIconOnlyMenuItem(menuItem)) { 1140b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki button = menuItemButton.findViewById(R.id.floating_toolbar_menu_item_image_button); 1141b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1142b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki button.setTag(menuItem); 1143b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki button.setOnClickListener(mMenuItemButtonOnClickListener); 1144b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1145517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1146517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1147517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1148517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1149517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * A widget that holds the overflow items in the floating toolbar. 1150517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1151517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static final class FloatingToolbarOverflowPanel { 1152517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1153517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final LinearLayout mContentView; 1154517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final ViewGroup mBackButtonContainer; 1155517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final View mBackButton; 1156517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final ListView mListView; 1157f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki private final TextView mListViewItemWidthCalculator; 1158517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final ViewFader mViewFader; 1159517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final Runnable mCloseOverflow; 1160517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1161517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener; 11628747f37383c41805800d208c8a4ebeeebeddf2dcAbodunrinwa Toki private int mOverflowWidth; 1163ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki private int mSuggestedHeight; 1164517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1165517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1166517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Initializes a floating toolbar popup overflow view panel. 11670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * 1168517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param context 1169517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param closeOverflow The code that closes the toolbar popup's overflow. 1170517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1171517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) { 1172517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mCloseOverflow = Preconditions.checkNotNull(closeOverflow); 1173517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1174517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView = new LinearLayout(context); 1175517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.setOrientation(LinearLayout.VERTICAL); 1176517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mViewFader = new ViewFader(mContentView); 1177517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1178517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mBackButton = LayoutInflater.from(context) 1179517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki .inflate(R.layout.floating_popup_close_overflow_button, null); 1180517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mBackButton.setOnClickListener(new View.OnClickListener() { 1181517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 1182517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onClick(View v) { 1183517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mCloseOverflow.run(); 1184517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1185517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }); 1186517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mBackButtonContainer = new LinearLayout(context); 1187517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mBackButtonContainer.addView(mBackButton); 1188517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1189f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mListView = createOverflowListView(); 1190517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 1191517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 1192517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 1193517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(position); 1194517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (mOnMenuItemClickListener != null) { 1195517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOnMenuItemClickListener.onMenuItemClick(menuItem); 1196517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1197517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1198517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }); 1199517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1200517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.addView(mListView); 1201517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.addView(mBackButtonContainer); 1202f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki 1203f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mListViewItemWidthCalculator = createOverflowMenuItemButton(context); 1204f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mListViewItemWidthCalculator.setLayoutParams(new ViewGroup.LayoutParams( 1205f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 1206517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1207517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1208517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1209517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Sets the menu items to be displayed in the overflow. 12100c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1211517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void setMenuItems(List<MenuItem> menuItems) { 1212517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ArrayAdapter overflowListViewAdapter = (ArrayAdapter) mListView.getAdapter(); 1213517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki overflowListViewAdapter.clear(); 1214517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki overflowListViewAdapter.addAll(menuItems); 1215517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki setListViewHeight(); 1216f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki setOverflowWidth(); 1217517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1218517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1219517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) { 1220517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mOnMenuItemClickListener = listener; 12210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 12220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 12230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1224517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Notifies the overflow of the current direction in which the overflow will be opened. 12250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * 1226517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param overflowDirection {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_UP} 1227517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * or {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_DOWN}. 12280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1229517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void setOverflowDirection(int overflowDirection) { 1230517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.removeView(mBackButtonContainer); 1231517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int index = (overflowDirection == FloatingToolbarPopup.OVERFLOW_DIRECTION_UP)? 1 : 0; 1232517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.addView(mBackButtonContainer, index); 12330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 12340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki 1235ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki public void setSuggestedHeight(int height) { 1236ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki mSuggestedHeight = height; 1237ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki setListViewHeight(); 1238ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 1239ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki 12406d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki public int getMinimumHeight() { 12416d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki return mContentView.getContext().getResources(). 12426d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height) 12436d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki + getEstimatedToolbarHeight(mContentView.getContext()); 12446d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } 12456d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki 12460c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki /** 1247517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Returns the content view of the overflow. 1248517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1249517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public View getView() { 1250517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return mContentView; 1251517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1252517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1253517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void fadeIn(boolean animate) { 1254517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mViewFader.fadeIn(animate); 1255517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1256517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1257517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void fadeOut(boolean animate) { 1258517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mViewFader.fadeOut(animate); 1259517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1260517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1261517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1262517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Returns how big this panel's view should be. 1263517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * This method should only be called when the view has not been attached to a parent. 12640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * 1265517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @throws IllegalStateException 12660c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */ 1267517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public Size measure() { 1268517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Preconditions.checkState(mContentView.getParent() == null); 1269517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 1270517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight()); 1271517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1272517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1273517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private void setListViewHeight() { 1274517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int itemHeight = getEstimatedToolbarHeight(mContentView.getContext()); 1275517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int height = mListView.getAdapter().getCount() * itemHeight; 1276517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki int maxHeight = mContentView.getContext().getResources(). 1277ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki getDimensionPixelSize(R.dimen.floating_toolbar_maximum_overflow_height); 1278ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki int minHeight = mContentView.getContext().getResources(). 1279517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height); 12806d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki int suggestedListViewHeight = mSuggestedHeight - (mSuggestedHeight % itemHeight) 1281ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki - itemHeight; // reserve space for the back button. 1282517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams params = mListView.getLayoutParams(); 12836d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki if (suggestedListViewHeight <= 0) { 12846d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Invalid height. Use the maximum height available. 1285ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki params.height = Math.min(maxHeight, height); 12866d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } else if (suggestedListViewHeight < minHeight) { 12876d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Height is smaller than minimum allowed. Use minimum height. 12886d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki params.height = minHeight; 12896d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki } else { 12906d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki // Use the suggested height. Cap it at the maximum available height. 12916d2b75c86d7007512a6ad935e5125b735106d90aAbodunrinwa Toki params.height = Math.min(Math.min(suggestedListViewHeight, maxHeight), height); 1292ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki } 1293517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mListView.setLayoutParams(params); 12940c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki } 1295517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 12968747f37383c41805800d208c8a4ebeeebeddf2dcAbodunrinwa Toki private void setOverflowWidth() { 12978747f37383c41805800d208c8a4ebeeebeddf2dcAbodunrinwa Toki mOverflowWidth = 0; 1298f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki for (int i = 0; i < mListView.getAdapter().getCount(); i++) { 1299f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(i); 1300f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki Preconditions.checkNotNull(menuItem); 1301f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mListViewItemWidthCalculator.setText(menuItem.getTitle()); 1302f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mListViewItemWidthCalculator.measure( 1303f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); 1304f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mOverflowWidth = Math.max( 1305f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki mListViewItemWidthCalculator.getMeasuredWidth(), mOverflowWidth); 1306f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki } 1307f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki } 1308f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki 1309f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki private ListView createOverflowListView() { 1310f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki final Context context = mContentView.getContext(); 1311517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final ListView overflowListView = new ListView(context); 1312517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki overflowListView.setLayoutParams(new ViewGroup.LayoutParams( 1313517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 1314517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki overflowListView.setDivider(null); 1315517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki overflowListView.setDividerHeight(0); 1316b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki 1317b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki final int viewTypeCount = 2; 1318b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki final int stringLabelViewType = 0; 1319b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki final int iconOnlyViewType = 1; 1320517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki final ArrayAdapter overflowListViewAdapter = 1321517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki new ArrayAdapter<MenuItem>(context, 0) { 1322517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki @Override 1323b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki public int getViewTypeCount() { 1324b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki return viewTypeCount; 1325b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1326b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki 1327b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki @Override 1328b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki public int getItemViewType(int position) { 1329b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki if (isIconOnlyMenuItem(getItem(position))) { 1330b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki return iconOnlyViewType; 1331b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1332b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki return stringLabelViewType; 1333b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1334b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki 1335b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki @Override 1336517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public View getView(int position, View convertView, ViewGroup parent) { 1337b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki if (getItemViewType(position) == iconOnlyViewType) { 1338b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki return getIconOnlyView(position, convertView); 1339b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1340b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki return getStringTitleView(position, convertView); 1341b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1342b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki 1343b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki private View getStringTitleView(int position, View convertView) { 1344517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki TextView menuButton; 1345517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (convertView != null) { 1346517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuButton = (TextView) convertView; 1347517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } else { 1348517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuButton = createOverflowMenuItemButton(context); 1349517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1350517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki MenuItem menuItem = getItem(position); 1351517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuButton.setText(menuItem.getTitle()); 1352517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuButton.setContentDescription(menuItem.getTitle()); 1353f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki menuButton.setMinimumWidth(mOverflowWidth); 1354517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return menuButton; 1355517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1356b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki 1357b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki private View getIconOnlyView(int position, View convertView) { 1358b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki View menuButton; 1359b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki if (convertView != null) { 1360b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki menuButton = convertView; 1361b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } else { 1362b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki menuButton = LayoutInflater.from(context).inflate( 1363b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki R.layout.floating_popup_overflow_image_list_item, null); 1364b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1365b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki MenuItem menuItem = getItem(position); 1366b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki ((ImageView) menuButton 1367b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki .findViewById(R.id.floating_toolbar_menu_item_image_button)) 1368b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki .setImageDrawable(menuItem.getIcon()); 1369b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki menuButton.setMinimumWidth(mOverflowWidth); 1370b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki return menuButton; 1371b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1372517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki }; 1373517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki overflowListView.setAdapter(overflowListViewAdapter); 1374517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return overflowListView; 1375517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1376517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1377517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1378517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1379517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1380517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * A helper for fading in or out a view. 1381517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1382517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static final class ViewFader { 1383517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1384517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static final int FADE_OUT_DURATION = 250; 1385517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static final int FADE_IN_DURATION = 150; 1386517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1387517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final View mView; 1388517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final ObjectAnimator mFadeOutAnimation; 1389517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private final ObjectAnimator mFadeInAnimation; 1390517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1391517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private ViewFader(View view) { 1392517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mView = Preconditions.checkNotNull(view); 1393517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mFadeOutAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0) 1394517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki .setDuration(FADE_OUT_DURATION); 1395517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mFadeInAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1) 1396517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki .setDuration(FADE_IN_DURATION); 1397517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1398517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1399517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void fadeIn(boolean animate) { 1400b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki cancelFadeAnimations(); 1401517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (animate) { 1402517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mFadeInAnimation.start(); 1403517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } else { 1404517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mView.setAlpha(1); 1405517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1406517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1407517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1408517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki public void fadeOut(boolean animate) { 1409b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki cancelFadeAnimations(); 1410517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki if (animate) { 1411517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mFadeOutAnimation.start(); 1412517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } else { 1413517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki mView.setAlpha(0); 1414517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1415517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1416b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki 1417b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki private void cancelFadeAnimations() { 1418b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mFadeInAnimation.cancel(); 1419b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki mFadeOutAnimation.cancel(); 1420b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki } 1421517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1422517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1423b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki /** 1424b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki * @return {@code true} if the menu item does not not have a string title but has an icon. 1425b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki * {@code false} otherwise. 1426b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki */ 1427b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki private static boolean isIconOnlyMenuItem(MenuItem menuItem) { 1428b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki if (TextUtils.isEmpty(menuItem.getTitle()) && menuItem.getIcon() != null) { 1429b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki return true; 1430b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1431b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki return false; 1432b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1433517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1434517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1435517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Creates and returns a menu button for the specified menu item. 1436517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1437b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki private static View createMenuItemButton(Context context, MenuItem menuItem) { 1438b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki if (isIconOnlyMenuItem(menuItem)) { 1439b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki View imageMenuItemButton = LayoutInflater.from(context) 1440b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki .inflate(R.layout.floating_popup_menu_image_button, null); 1441b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki ((ImageButton) imageMenuItemButton 1442b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki .findViewById(R.id.floating_toolbar_menu_item_image_button)) 1443b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki .setImageDrawable(menuItem.getIcon()); 1444b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki return imageMenuItemButton; 1445b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki } 1446b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki 1447517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki Button menuItemButton = (Button) LayoutInflater.from(context) 1448517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki .inflate(R.layout.floating_popup_menu_button, null); 1449517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.setText(menuItem.getTitle()); 1450517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki menuItemButton.setContentDescription(menuItem.getTitle()); 1451517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return menuItemButton; 1452517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1453517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1454517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 1455517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * Creates and returns a styled floating toolbar overflow list view item. 1456517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 1457517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static TextView createOverflowMenuItemButton(Context context) { 1458517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return (TextView) LayoutInflater.from(context) 1459517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki .inflate(R.layout.floating_popup_overflow_list_item, null); 1460517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1461517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1462517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static ViewGroup createContentContainer(Context context) { 1463517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return (ViewGroup) LayoutInflater.from(context) 1464517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki .inflate(R.layout.floating_popup_container, null); 1465517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1466517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1467517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static PopupWindow createPopupWindow(View content) { 1468517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup popupContentHolder = new LinearLayout(content.getContext()); 1469517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki PopupWindow popupWindow = new PopupWindow(popupContentHolder); 1470bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // TODO: Use .setLayoutInScreenEnabled(true) instead of .setClippingEnabled(false) 1471bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa // unless FLAG_LAYOUT_IN_SCREEN has any unintentional side-effects. 1472bafc908304d49e8f7f7c5e52772c75da66e4daa3Yohei Yukawa popupWindow.setClippingEnabled(false); 1473103d48ec09cbaeedf28b66425cde9198f767e0d5Abodunrinwa Toki popupWindow.setWindowLayoutType( 1474103d48ec09cbaeedf28b66425cde9198f767e0d5Abodunrinwa Toki WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL); 1475517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki popupWindow.setAnimationStyle(0); 1476517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 1477517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki content.setLayoutParams(new ViewGroup.LayoutParams( 1478517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 1479517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki popupContentHolder.addView(content); 1480517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return popupWindow; 1481517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1482517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1483517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 14847aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki * Creates an "appear" animation for the specified view. 1485517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 1486517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param view The view to animate 1487517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 14887aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki private static AnimatorSet createEnterAnimation(View view) { 14897aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki AnimatorSet animation = new AnimatorSet(); 14907aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki animation.playTogether( 1491a6200068af5810eb66580c4013a4940e40085bccAbodunrinwa Toki ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150), 14926c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki // Make sure that view.x is always fixed throughout the duration of this animation. 14936cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX())); 14947aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki return animation; 1495517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1496517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1497517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki /** 14987aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki * Creates a "disappear" animation for the specified view. 1499517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * 1500517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param view The view to animate 1501cdffaa4c5af71b4bd0c99a98d411ee3883ec4733Abodunrinwa Toki * @param startDelay The start delay of the animation 1502517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki * @param listener The animation listener 1503517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki */ 15047aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki private static AnimatorSet createExitAnimation( 1505cdffaa4c5af71b4bd0c99a98d411ee3883ec4733Abodunrinwa Toki View view, int startDelay, Animator.AnimatorListener listener) { 15067aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki AnimatorSet animation = new AnimatorSet(); 15077aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki animation.playTogether( 1508a6200068af5810eb66580c4013a4940e40085bccAbodunrinwa Toki ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100)); 15097aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki animation.setStartDelay(startDelay); 15107aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki animation.addListener(listener); 15117aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki return animation; 1512517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1513517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1514079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki /** 1515079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki * Returns a re-themed context with controlled look and feel for views. 1516079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki */ 1517079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki private static Context applyDefaultTheme(Context originalContext) { 1518079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki TypedArray a = originalContext.obtainStyledAttributes(new int[]{R.attr.isLightTheme}); 1519079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki boolean isLightTheme = a.getBoolean(0, true); 1520079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki int themeId = isLightTheme ? R.style.Theme_Material_Light : R.style.Theme_Material; 1521079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki a.recycle(); 1522079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki return new ContextThemeWrapper(originalContext, themeId); 1523079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki } 1524079f33bca029c440ec6e788d6b3185f850f57973Abodunrinwa Toki 1525517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static int getEstimatedToolbarHeight(Context context) { 1526517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return context.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_height); 1527517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 1528517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki 1529517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki private static int getEstimatedOpenOverflowButtonWidth(Context context) { 1530517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki return context.getResources() 1531517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki .getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_minimum_width); 1532517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki } 15330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki} 1534