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