FloatingToolbar.java revision 7aa6d0a4b1ec7f75335348a86284d3773cc72f91
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;
230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.content.Context;
240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.graphics.Color;
250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.graphics.Point;
260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.graphics.Rect;
27517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.graphics.Region;
280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.graphics.drawable.ColorDrawable;
29b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Tokiimport android.text.TextUtils;
30517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.util.Size;
310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Gravity;
320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.LayoutInflater;
330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Menu;
340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.MenuItem;
350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.View;
360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.View.MeasureSpec;
370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.ViewGroup;
38517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.ViewTreeObserver;
390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Window;
40e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Tokiimport android.view.WindowInsets;
41517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.WindowManager;
42517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.Animation;
43517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.AnimationSet;
44517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.Transformation;
45517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.AdapterView;
46517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.ArrayAdapter;
470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.Button;
480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.ImageButton;
49b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Tokiimport android.widget.ImageView;
500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.LinearLayout;
51517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.ListView;
520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.PopupWindow;
53517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.TextView;
540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.ArrayList;
560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.LinkedList;
570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.List;
580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
59517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport com.android.internal.R;
60517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport com.android.internal.util.Preconditions;
61517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki/**
630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * A floating toolbar for showing contextual menu items.
640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * This view shows as many menu item buttons as can fit in the horizontal toolbar and the
650c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * the remaining menu items in a vertical overflow view when the overflow button is clicked.
660c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The horizontal toolbar morphs into the vertical overflow view.
670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */
680c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokipublic final class FloatingToolbar {
690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
70517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    // This class is responsible for the public API of the floating toolbar.
71517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    // It delegates rendering operations to the FloatingToolbarPopup.
72517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER =
740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            new MenuItem.OnMenuItemClickListener() {
750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                @Override
760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                public boolean onMenuItemClick(MenuItem item) {
770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    return false;
780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                }
790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            };
800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
810c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private final Context mContext;
820c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private final FloatingToolbarPopup mPopup;
830c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
840c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private final Rect mContentRect = new Rect();
850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private Menu mMenu;
875047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki    private List<Object> mShowingMenuItems = new ArrayList<Object>();
880c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
890c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
900c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private int mSuggestedWidth;
91517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private boolean mWidthChanged = true;
920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
940c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Initializes a floating toolbar.
950c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
960c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar(Context context, Window window) {
970c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mContext = Preconditions.checkNotNull(context);
98517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        mPopup = new FloatingToolbarPopup(window.getDecorView());
990c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1000c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1010c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1020c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Sets the menu to be shown in this floating toolbar.
1030c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
1040c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * toolbar.
1050c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1060c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar setMenu(Menu menu) {
1070c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mMenu = Preconditions.checkNotNull(menu);
1080c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1090c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1100c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1110c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1127270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Sets the custom listener for invocation of menu items in this floating toolbar.
1130c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1140c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar setOnMenuItemClickListener(
1150c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            MenuItem.OnMenuItemClickListener menuItemClickListener) {
1160c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        if (menuItemClickListener != null) {
1170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mMenuItemClickListener = menuItemClickListener;
1180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        } else {
1190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
1200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
1210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Sets the content rectangle. This is the area of the interesting content that this toolbar
1260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * should avoid obstructing.
1270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
1280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * toolbar.
1290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar setContentRect(Rect rect) {
1310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mContentRect.set(Preconditions.checkNotNull(rect));
1320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Sets the suggested width of this floating toolbar.
1370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * The actual width will be about this size but there are no guarantees that it will be exactly
1380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * the suggested width.
1390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
1400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * toolbar.
1410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1420c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar setSuggestedWidth(int suggestedWidth) {
143517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        // Check if there's been a substantial width spec change.
144517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        int difference = Math.abs(suggestedWidth - mSuggestedWidth);
145517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        mWidthChanged = difference > (mSuggestedWidth * 0.2);
146517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mSuggestedWidth = suggestedWidth;
1480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Shows this floating toolbar.
1530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar show() {
1550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
156517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        if (!isCurrentlyShowing(menuItems) || mWidthChanged) {
1570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mPopup.dismiss();
158517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth);
1595047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki            mShowingMenuItems = getShowingMenuItemsReferences(menuItems);
1600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
161ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        mPopup.updateCoordinates(mContentRect);
1620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        if (!mPopup.isShowing()) {
163ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            mPopup.show(mContentRect);
1640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
165517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        mWidthChanged = false;
1660c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1680c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Updates this floating toolbar to reflect recent position and view updates.
1710c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * NOTE: This method is a no-op if the toolbar isn't showing.
1720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar updateLayout() {
1740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        if (mPopup.isShowing()) {
1750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            // show() performs all the logic we need here.
1760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            show();
1770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
1780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1810c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1820c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Dismisses this floating toolbar.
1830c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1840c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public void dismiss() {
1850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mPopup.dismiss();
1860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1870c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1880c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1897270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Hides this floating toolbar. This is a no-op if the toolbar is not showing.
1907270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Use {@link #isHidden()} to distinguish between a hidden and a dismissed toolbar.
1917270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     */
1927270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    public void hide() {
1937270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        mPopup.hide();
1947270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    }
1957270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
1967270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    /**
1977270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Returns {@code true} if this toolbar is currently showing. {@code false} otherwise.
1980c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1990c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public boolean isShowing() {
2000c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return mPopup.isShowing();
2010c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
2020c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2030c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
2047270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Returns {@code true} if this toolbar is currently hidden. {@code false} otherwise.
2057270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     */
2067270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    public boolean isHidden() {
2077270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        return mPopup.isHidden();
2087270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    }
2097270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
2107270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    /**
211517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Returns true if this floating toolbar is currently showing the specified menu items.
2120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
213517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private boolean isCurrentlyShowing(List<MenuItem> menuItems) {
2145047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki        return mShowingMenuItems.equals(getShowingMenuItemsReferences(menuItems));
2150c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
2160c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
2180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Returns the visible and enabled menu items in the specified menu.
2190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * This method is recursive.
2200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
2210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private List<MenuItem> getVisibleAndEnabledMenuItems(Menu menu) {
2220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        List<MenuItem> menuItems = new ArrayList<MenuItem>();
2230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        for (int i = 0; (menu != null) && (i < menu.size()); i++) {
2240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            MenuItem menuItem = menu.getItem(i);
2250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            if (menuItem.isVisible() && menuItem.isEnabled()) {
2260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                Menu subMenu = menuItem.getSubMenu();
2270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                if (subMenu != null) {
2280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    menuItems.addAll(getVisibleAndEnabledMenuItems(subMenu));
2290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                } else {
2300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    menuItems.add(menuItem);
2310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                }
2320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            }
2330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
2340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return menuItems;
2350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
2360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2375047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki    private List<Object> getShowingMenuItemsReferences(List<MenuItem> menuItems) {
2385047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki        List<Object> references = new ArrayList<Object>();
2390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        for (MenuItem menuItem : menuItems) {
2405047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki            if (isIconOnlyMenuItem(menuItem)) {
2415047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki                references.add(menuItem.getIcon());
2425047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki            } else {
2435047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki                references.add(menuItem.getTitle());
2445047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki            }
2450c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
2465047132887112df4235beea8ff42a28f1653e202Abodunrinwa Toki        return references;
2470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
2480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
251517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * A popup window used by the floating toolbar.
252517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     *
253517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * This class is responsible for the rendering/animation of the floating toolbar.
254517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * It can hold one of 2 panels (i.e. main panel and overflow panel) at a time.
255517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * It delegates specific panel functionality to the appropriate panel.
2560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
257517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static final class FloatingToolbarPopup {
2580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
259517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public static final int OVERFLOW_DIRECTION_UP = 0;
260517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public static final int OVERFLOW_DIRECTION_DOWN = 1;
2610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
262517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final View mParent;
263517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final PopupWindow mPopupWindow;
264517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewGroup mContentContainer;
265f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private final int mMarginHorizontal;
266f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private final int mMarginVertical;
2670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
268517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Animation.AnimationListener mOnOverflowOpened =
269517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                new Animation.AnimationListener() {
270517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
271517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationStart(Animation animation) {}
2720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
273517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
274517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationEnd(Animation animation) {
275b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                        setOverflowPanelAsContent();
276517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mOverflowPanel.fadeIn(true);
277517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
2780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
279517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
280517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationRepeat(Animation animation) {}
281517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                };
282517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Animation.AnimationListener mOnOverflowClosed =
283517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                new Animation.AnimationListener() {
284517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
285517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationStart(Animation animation) {}
2860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
287517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
288517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationEnd(Animation animation) {
289b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                        setMainPanelAsContent();
290517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mMainPanel.fadeIn(true);
291517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
2920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    @Override
294517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationRepeat(Animation animation) {
2950c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    }
2960c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                };
2977270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private final AnimatorSet mDismissAnimation;
2987270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private final AnimatorSet mHideAnimation;
299b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private final AnimationSet mOpenOverflowAnimation = new AnimationSet(true) {
300b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            @Override
301b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            public void cancel() {
302b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                if (hasStarted() && !hasEnded()) {
303b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    super.cancel();
304b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    setOverflowPanelAsContent();
305b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                }
306b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            }
307b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        };
308b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private final AnimationSet mCloseOverflowAnimation = new AnimationSet(true) {
309b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            @Override
310b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            public void cancel() {
311b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                if (hasStarted() && !hasEnded()) {
312b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    super.cancel();
313b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    setMainPanelAsContent();
314b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                }
315b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            }
316b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        };
3170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
318517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Runnable mOpenOverflow = new Runnable() {
319517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            @Override
320517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            public void run() {
321517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                openOverflow();
322517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
323517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        };
324517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Runnable mCloseOverflow = new Runnable() {
325517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            @Override
326517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            public void run() {
327517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                closeOverflow();
328517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
329517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        };
330517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
331e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki        private final Rect mViewPort = new Rect();
332ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        private final Point mCoords = new Point();
333ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
334517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Region mTouchableRegion = new Region();
335d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki        private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
336d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                new ViewTreeObserver.OnComputeInternalInsetsListener() {
337d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                    public void onComputeInternalInsets(
338d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                            ViewTreeObserver.InternalInsetsInfo info) {
339d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                        info.contentInsets.setEmpty();
340d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                        info.visibleInsets.setEmpty();
341d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                        info.touchableRegion.set(mTouchableRegion);
342d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                        info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo
343d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                                .TOUCHABLE_INSETS_REGION);
344d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                    }
345d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                };
346517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
3477270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private boolean mDismissed = true; // tracks whether this popup is dismissed or dismissing.
3487270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private boolean mHidden; // tracks whether this popup is hidden or hiding.
3490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
350517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private FloatingToolbarOverflowPanel mOverflowPanel;
351517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private FloatingToolbarMainPanel mMainPanel;
352517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private int mOverflowDirection;
353517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
3540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
355517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Initializes a new floating toolbar popup.
3560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         *
357517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param parent  A parent view to get the {@link android.view.View#getWindowToken()} token
358517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *      from.
3590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
3600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public FloatingToolbarPopup(View parent) {
3610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mParent = Preconditions.checkNotNull(parent);
3620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mContentContainer = createContentContainer(parent.getContext());
3630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mPopupWindow = createPopupWindow(mContentContainer);
3647aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki            mDismissAnimation = createExitAnimation(
365517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer,
3664ce050bd83b8c311d7cf7b50e0a36a28df68bc4aAbodunrinwa Toki                    150,  // startDelay
367517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    new AnimatorListenerAdapter() {
368517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        @Override
369517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        public void onAnimationEnd(Animator animation) {
370517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            mPopupWindow.dismiss();
371b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                            mContentContainer.removeAllViews();
372517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        }
373517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    });
3747aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki            mHideAnimation = createExitAnimation(
3757270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                    mContentContainer,
3764ce050bd83b8c311d7cf7b50e0a36a28df68bc4aAbodunrinwa Toki                    0,  // startDelay
3777270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                    new AnimatorListenerAdapter() {
3787270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                        @Override
3797270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                        public void onAnimationEnd(Animator animation) {
3807270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                            mPopupWindow.dismiss();
3817270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                        }
3827270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                    });
3836cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki            mMarginHorizontal = parent.getResources()
3846cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki                    .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
3856cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki            mMarginVertical = parent.getResources()
3866cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki                    .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin);
387517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
388517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
389517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
390517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Lays out buttons for the specified menu items.
391517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
3926c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki        public void layoutMenuItems(
3936c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                List<MenuItem> menuItems,
3946c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                MenuItem.OnMenuItemClickListener menuItemClickListener,
3956c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                int suggestedWidth) {
396ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            Preconditions.checkNotNull(menuItems);
397ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
398517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentContainer.removeAllViews();
399517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (mMainPanel == null) {
400517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow);
401517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
402517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            List<MenuItem> overflowMenuItems =
403e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki                    mMainPanel.layoutMenuItems(menuItems, getToolbarWidth(suggestedWidth));
404517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mMainPanel.setOnMenuItemClickListener(menuItemClickListener);
405517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (!overflowMenuItems.isEmpty()) {
406517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                if (mOverflowPanel == null) {
407517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mOverflowPanel =
408517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            new FloatingToolbarOverflowPanel(mParent.getContext(), mCloseOverflow);
409517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
410517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mOverflowPanel.setMenuItems(overflowMenuItems);
411517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mOverflowPanel.setOnMenuItemClickListener(menuItemClickListener);
412517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
413517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            updatePopupSize();
4140c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
4150c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4160c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
4170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Shows this popup at the specified coordinates.
4180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
4190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
420ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        public void show(Rect contentRect) {
421ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            Preconditions.checkNotNull(contentRect);
422ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
4230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            if (isShowing()) {
4240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                return;
4250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            }
4260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4277270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHidden = false;
4287270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mDismissed = false;
4290ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki            cancelDismissAndHideAnimations();
4300ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki            cancelOverflowAnimations();
431ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
432b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // Make sure a panel is set as the content.
433b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            if (mContentContainer.getChildCount() == 0) {
434b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                setMainPanelAsContent();
435c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki                // If we're yet to show the popup, set the container visibility to zero.
436c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki                // The "show" animation will make this visible.
437c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki                mContentContainer.setAlpha(0);
438b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            }
439e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            refreshViewPort();
440e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            updateOverflowHeight(contentRect.top - (mMarginVertical * 2) - mViewPort.top);
441ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            refreshCoordinatesAndOverflowDirection(contentRect);
442517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            preparePopupContent();
443ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, mCoords.x, mCoords.y);
444d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki            setTouchableSurfaceInsetsComputer();
4457270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            runShowAnimation();
4460c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
4470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
4490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
4500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
4510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public void dismiss() {
4520ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki            if (mDismissed) {
4530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                return;
4540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            }
4550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4567270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHidden = false;
4577270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mDismissed = true;
4580ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki            mHideAnimation.cancel();
4597270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            runDismissAnimation();
4607270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            setZeroTouchableSurface();
4617270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        }
4627270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
4637270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        /**
4647270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Hides this popup. This is a no-op if this popup is not showing.
4657270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup.
4667270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         */
4677270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        public void hide() {
4687270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            if (!isShowing()) {
4697270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                return;
4707270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            }
4717270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
4727270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHidden = true;
4737270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            runHideAnimation();
474517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            setZeroTouchableSurface();
4750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
4760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
4780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
4790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
4800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public boolean isShowing() {
481c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki            return !mDismissed && !mHidden;
4827270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        }
4837270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
4847270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        /**
4857270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Returns {@code true} if this popup is currently hidden. {@code false} otherwise.
4867270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         */
4877270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        public boolean isHidden() {
4887270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            return mHidden;
4890c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
4900c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4910c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
4920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Updates the coordinates of this popup.
4930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
4947270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * This is a no-op if this popup is not showing.
4950c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
496ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        public void updateCoordinates(Rect contentRect) {
497ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            Preconditions.checkNotNull(contentRect);
498ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
499c23ac32601af1c7a5877d99c221e7e79e0ed1c90Abodunrinwa Toki            if (!isShowing() || !mPopupWindow.isShowing()) {
500517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                return;
5010c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            }
502517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
5030ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki            cancelOverflowAnimations();
504e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            refreshViewPort();
505ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            refreshCoordinatesAndOverflowDirection(contentRect);
506517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            preparePopupContent();
507ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            mPopupWindow.update(mCoords.x, mCoords.y, getWidth(), getHeight());
5080c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5090c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5100c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5110c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Returns the width of this popup.
5120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5130c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public int getWidth() {
514517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return mPopupWindow.getWidth();
5150c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5160c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Returns the height of this popup.
5190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public int getHeight() {
521517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return mPopupWindow.getHeight();
5220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Returns the context this popup is running in.
5260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public Context getContext() {
5280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            return mContentContainer.getContext();
5290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
531ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        private void refreshCoordinatesAndOverflowDirection(Rect contentRect) {
532e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            // NOTE: Ensure that mViewPort has been refreshed before this.
533e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki
534ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            int x = contentRect.centerX() - getWidth() / 2;
535ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            int y;
536e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            if (contentRect.top - getHeight() > mViewPort.top) {
537ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                y = contentRect.top - getHeight();
538ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP;
539e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            } else if (contentRect.top - getToolbarHeightWithVerticalMargin() > mViewPort.top) {
540ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                y = contentRect.top - getToolbarHeightWithVerticalMargin();
541ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
542ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            } else {
543ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                y = contentRect.bottom;
544ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
545ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            }
546e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki
547e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            // Update x so that the toolbar isn't rendered behind the nav bar in landscape.
548e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            x = Math.max(0, Math.min(x, mViewPort.right - getWidth()));
549e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki
550ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            mCoords.set(x, y);
551ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            if (mOverflowPanel != null) {
552ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                mOverflowPanel.setOverflowDirection(mOverflowDirection);
553ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            }
554ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        }
555ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
556ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        private int getToolbarHeightWithVerticalMargin() {
557f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            return getEstimatedToolbarHeight(mParent.getContext()) + mMarginVertical * 2;
558f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        }
559f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki
5600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5617270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Performs the "show" animation on the floating popup.
5627270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         */
5637270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private void runShowAnimation() {
5647aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki            createEnterAnimation(mContentContainer).start();
5657270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        }
5667270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
5677270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        /**
5687270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Performs the "dismiss" animation on the floating popup.
5690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5707270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private void runDismissAnimation() {
5717270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mDismissAnimation.start();
5720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5757270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Performs the "hide" animation on the floating popup.
5760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5777270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private void runHideAnimation() {
5787270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHideAnimation.start();
5790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5810ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki        private void cancelDismissAndHideAnimations() {
5827270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mDismissAnimation.cancel();
5837270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHideAnimation.cancel();
5840ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki        }
5850ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki
5860ce3e08a8444c73e63a0f733357581fb4409449aAbodunrinwa Toki        private void cancelOverflowAnimations() {
587b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.cancel();
588b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.cancel();
589517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
590517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
591517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
592517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Opens the floating toolbar overflow.
593517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * This method should not be called if menu items have not been laid out with
594b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}.
595517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *
596517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @throws IllegalStateException if called when menu items have not been laid out.
597517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
598517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void openOverflow() {
599b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkState(mMainPanel != null);
600b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkState(mOverflowPanel != null);
601517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
602517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mMainPanel.fadeOut(true);
603517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Size overflowPanelSize = mOverflowPanel.measure();
604f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            final int targetWidth = overflowPanelSize.getWidth();
605517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int targetHeight = overflowPanelSize.getHeight();
606517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final boolean morphUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP);
607517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int startWidth = mContentContainer.getWidth();
608517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int startHeight = mContentContainer.getHeight();
609517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final float startY = mContentContainer.getY();
6106c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki            final float left = mContentContainer.getX();
6116c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki            final float right = left + mContentContainer.getWidth();
612517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Animation widthAnimation = new Animation() {
613517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
614517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                protected void applyTransformation(float interpolatedTime, Transformation t) {
615517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
616517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
617517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.width = startWidth + deltaWidth;
618517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setLayoutParams(params);
6196cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki                    if (isRTL()) {
6206c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                        mContentContainer.setX(left);
6216c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                    } else {
6226c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                        mContentContainer.setX(right - mContentContainer.getWidth());
6236c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                    }
624517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
625517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            };
626517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Animation heightAnimation = new Animation() {
627517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
628517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                protected void applyTransformation(float interpolatedTime, Transformation t) {
629517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
630517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
631517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.height = startHeight + deltaHeight;
632517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setLayoutParams(params);
633517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    if (morphUpwards) {
634517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        float y = startY - (mContentContainer.getHeight() - startHeight);
635517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mContentContainer.setY(y);
636517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
637517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
638517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            };
639517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            widthAnimation.setDuration(240);
640517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            heightAnimation.setDuration(180);
641517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            heightAnimation.setStartOffset(60);
642b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.getAnimations().clear();
643b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.setAnimationListener(mOnOverflowOpened);
644b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.addAnimation(widthAnimation);
645b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.addAnimation(heightAnimation);
646b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.startAnimation(mOpenOverflowAnimation);
647517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
648517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
649517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
650517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Opens the floating toolbar overflow.
651517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * This method should not be called if menu items have not been laid out with
652517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}.
653517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *
654b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * @throws IllegalStateException if called when menu items have not been laid out.
655517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
656517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void closeOverflow() {
657b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkState(mMainPanel != null);
658b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkState(mOverflowPanel != null);
659517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
660517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOverflowPanel.fadeOut(true);
661517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Size mainPanelSize = mMainPanel.measure();
662517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int targetWidth = mainPanelSize.getWidth();
663517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int targetHeight = mainPanelSize.getHeight();
664517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int startWidth = mContentContainer.getWidth();
665517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int startHeight = mContentContainer.getHeight();
666517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final float bottom = mContentContainer.getY() + mContentContainer.getHeight();
667517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final boolean morphedUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP);
6686c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki            final float left = mContentContainer.getX();
6696c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki            final float right = left + mContentContainer.getWidth();
670517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Animation widthAnimation = new Animation() {
671517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
672517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                protected void applyTransformation(float interpolatedTime, Transformation t) {
673517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
674517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
675517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.width = startWidth + deltaWidth;
676517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setLayoutParams(params);
6776cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki                    if (isRTL()) {
6786c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                        mContentContainer.setX(left);
6796c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                    } else {
6806c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                        mContentContainer.setX(right - mContentContainer.getWidth());
6816c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                    }
682517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
683517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            };
684517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Animation heightAnimation = new Animation() {
685517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
686517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                protected void applyTransformation(float interpolatedTime, Transformation t) {
687517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
688517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
689517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.height = startHeight + deltaHeight;
690517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setLayoutParams(params);
691517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    if (morphedUpwards) {
692517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mContentContainer.setY(bottom - mContentContainer.getHeight());
693517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
694517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
695517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            };
696517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            widthAnimation.setDuration(150);
697517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            widthAnimation.setStartOffset(150);
698517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            heightAnimation.setDuration(210);
699b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.getAnimations().clear();
700b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.setAnimationListener(mOnOverflowClosed);
701b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.addAnimation(widthAnimation);
702b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.addAnimation(heightAnimation);
703b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.startAnimation(mCloseOverflowAnimation);
704517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
705517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
706517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
707517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Prepares the content container for show and update calls.
708517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
709517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void preparePopupContent() {
710b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // Reset visibility.
711b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            if (mMainPanel != null) {
712b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                mMainPanel.fadeIn(false);
713517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
714517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (mOverflowPanel != null) {
715517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mOverflowPanel.fadeIn(false);
716517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
717517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
718b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // Reset position.
719ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            if (isMainPanelContent()) {
720b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                positionMainPanel();
721517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
722ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            if (isOverflowPanelContent()) {
723b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                positionOverflowPanel();
724517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
725517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
726517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
727ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        private boolean isMainPanelContent() {
728ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            return mMainPanel != null
729ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                    && mContentContainer.getChildAt(0) == mMainPanel.getView();
730ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        }
731ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
732ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        private boolean isOverflowPanelContent() {
733ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            return mOverflowPanel != null
734ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                    && mContentContainer.getChildAt(0) == mOverflowPanel.getView();
735ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        }
736ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
737517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
738517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Sets the current content to be the main view panel.
739517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
740517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void setMainPanelAsContent() {
741b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // This should never be called if the main panel has not been initialized.
742b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkNotNull(mMainPanel);
743517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentContainer.removeAllViews();
744517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Size mainPanelSize = mMainPanel.measure();
745517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
746517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            params.width = mainPanelSize.getWidth();
747517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            params.height = mainPanelSize.getHeight();
748517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentContainer.setLayoutParams(params);
749517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentContainer.addView(mMainPanel.getView());
750b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            setContentAreaAsTouchableSurface();
751b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        }
752b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
753b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        /**
754b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * Sets the current content to be the overflow view panel.
755b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         */
756b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private void setOverflowPanelAsContent() {
757b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // This should never be called if the overflow panel has not been initialized.
758b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkNotNull(mOverflowPanel);
759b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.removeAllViews();
760b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Size overflowPanelSize = mOverflowPanel.measure();
761b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
762b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            params.width = overflowPanelSize.getWidth();
763b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            params.height = overflowPanelSize.getHeight();
764b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setLayoutParams(params);
765b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.addView(mOverflowPanel.getView());
766b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            setContentAreaAsTouchableSurface();
767b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        }
768b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
769b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        /**
770b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * Places the main view panel at the appropriate resting coordinates.
771b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         */
772b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private void positionMainPanel() {
773b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkNotNull(mMainPanel);
7746c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki            mContentContainer.setX(mMarginHorizontal);
775b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
776b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            float y = mMarginVertical;
777b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            if  (mOverflowDirection == OVERFLOW_DIRECTION_UP) {
778b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                y = getHeight()
779b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                        - (mMainPanel.getView().getMeasuredHeight() + mMarginVertical);
780b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            }
781b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setY(y);
782b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            setContentAreaAsTouchableSurface();
783b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        }
784b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
785b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        /**
786b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * Places the main view panel at the appropriate resting coordinates.
787b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         */
788b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private void positionOverflowPanel() {
789b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkNotNull(mOverflowPanel);
7906cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki            float x;
7916cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki            if (isRTL()) {
7926cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki                x = mMarginHorizontal;
7936cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki            } else {
7946cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki                x = mPopupWindow.getWidth()
795b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    - (mOverflowPanel.getView().getMeasuredWidth() + mMarginHorizontal);
7966cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki            }
797b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setX(x);
798b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setY(mMarginVertical);
799b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            setContentAreaAsTouchableSurface();
800517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
801517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
802ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        private void updateOverflowHeight(int height) {
803ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            if (mOverflowPanel != null) {
804ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                mOverflowPanel.setSuggestedHeight(height);
805ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
806ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                // Re-measure the popup and it's contents.
807ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                boolean mainPanelContent = isMainPanelContent();
808ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                boolean overflowPanelContent = isOverflowPanelContent();
809ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                mContentContainer.removeAllViews();  // required to update popup size.
810ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                updatePopupSize();
811ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                // Reset the appropriate content.
812ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                if (mainPanelContent) {
813ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                    setMainPanelAsContent();
814ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                }
815ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                if (overflowPanelContent) {
816ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                    setOverflowPanelAsContent();
817ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                }
818ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            }
819ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        }
820ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
821517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void updatePopupSize() {
822517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int width = 0;
823517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int height = 0;
824517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (mMainPanel != null) {
825517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                Size mainPanelSize = mMainPanel.measure();
826517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                width = mainPanelSize.getWidth();
827517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                height = mainPanelSize.getHeight();
828517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
829517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (mOverflowPanel != null) {
830517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                Size overflowPanelSize = mOverflowPanel.measure();
831517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                width = Math.max(width, overflowPanelSize.getWidth());
832517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                height = Math.max(height, overflowPanelSize.getHeight());
833517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
834f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mPopupWindow.setWidth(width + mMarginHorizontal * 2);
835f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mPopupWindow.setHeight(height + mMarginVertical * 2);
836517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
837517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
838e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki
839e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki        private void refreshViewPort() {
840e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            mParent.getGlobalVisibleRect(mViewPort);
841e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            WindowInsets windowInsets = mParent.getRootWindowInsets();
842e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            mViewPort.set(
843e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki                    mViewPort.left + windowInsets.getStableInsetLeft(),
844e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki                    mViewPort.top + windowInsets.getStableInsetTop(),
845e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki                    mViewPort.right - windowInsets.getStableInsetRight(),
846e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki                    mViewPort.bottom - windowInsets.getStableInsetBottom());
847e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki        }
848e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki
849e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki        private int getToolbarWidth(int suggestedWidth) {
850e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            int width = suggestedWidth;
851e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            refreshViewPort();
852e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            int maximumWidth = mViewPort.width() - 2 * mParent.getResources()
853e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki                    .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
854e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            if (width <= 0) {
855e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki                width = mParent.getResources()
856e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki                        .getDimensionPixelSize(R.dimen.floating_toolbar_preferred_width);
857e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            }
858e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            return Math.min(width, maximumWidth);
859e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki        }
860e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki
861517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
862517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Sets the touchable region of this popup to be zero. This means that all touch events on
863517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * this popup will go through to the surface behind it.
864517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
865517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void setZeroTouchableSurface() {
866517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mTouchableRegion.setEmpty();
867517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
868517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
869517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
870517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Sets the touchable region of this popup to be the area occupied by its content.
871517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
872517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void setContentAreaAsTouchableSurface() {
873517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (!mPopupWindow.isShowing()) {
874517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
875517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
876517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int width = mContentContainer.getMeasuredWidth();
877517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int height = mContentContainer.getMeasuredHeight();
878517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mTouchableRegion.set(
879517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    (int) mContentContainer.getX(),
880517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    (int) mContentContainer.getY(),
881517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    (int) mContentContainer.getX() + width,
882517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    (int) mContentContainer.getY() + height);
883517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
884d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki
885d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki        /**
886d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki         * Make the touchable area of this popup be the area specified by mTouchableRegion.
887d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki         * This should be called after the popup window has been dismissed (dismiss/hide)
888d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki         * and is probably being re-shown with a new content root view.
889d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki         */
890d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki        private void setTouchableSurfaceInsetsComputer() {
891d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki            ViewTreeObserver viewTreeObserver = mPopupWindow.getContentView()
892d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                    .getRootView()
893d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                    .getViewTreeObserver();
894d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki            viewTreeObserver.removeOnComputeInternalInsetsListener(mInsetsComputer);
895d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki            viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer);
896d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki        }
8976cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki
8986cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki        private boolean isRTL() {
8996cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki            return mContentContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
9006cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki        }
901517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
902517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
903517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
904517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * A widget that holds the primary menu items in the floating toolbar.
905517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
906517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static final class FloatingToolbarMainPanel {
907517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
908517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Context mContext;
909517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewGroup mContentView;
910517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final View.OnClickListener mMenuItemButtonOnClickListener =
911517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                new View.OnClickListener() {
912517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
913517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onClick(View v) {
914517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        if (v.getTag() instanceof MenuItem) {
915517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            if (mOnMenuItemClickListener != null) {
916517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                mOnMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag());
917517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            }
918517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        }
919517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
920517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                };
921517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewFader viewFader;
922517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Runnable mOpenOverflow;
923517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
924517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private View mOpenOverflowButton;
925517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
926517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
927517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
928517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Initializes a floating toolbar popup main view panel.
929517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *
930517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param context
931517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param openOverflow  The code that opens the toolbar popup overflow.
932517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
933517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public FloatingToolbarMainPanel(Context context, Runnable openOverflow) {
934517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContext = Preconditions.checkNotNull(context);
935517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView = new LinearLayout(context);
936517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            viewFader = new ViewFader(mContentView);
937517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOpenOverflow = Preconditions.checkNotNull(openOverflow);
938517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
939517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
9400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
941517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Fits as many menu items in the main panel and returns a list of the menu items that
942517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * were not fit in.
943517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *
944517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @return The menu items that are not included in this main panel.
9450c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
946e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki        public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int width) {
947ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            Preconditions.checkNotNull(menuItems);
948ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
949e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            // Reserve space for the "open overflow" button.
950e3eb1833503c324127c621d22cbf7ac1729dbc54Abodunrinwa Toki            final int toolbarWidth = width - getEstimatedOpenOverflowButtonWidth(mContext);
951517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
952517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int availableWidth = toolbarWidth;
953517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
954517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
955517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.removeAllViews();
956517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
957517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            boolean isFirstItem = true;
958517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            while (!remainingMenuItems.isEmpty()) {
959517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                final MenuItem menuItem = remainingMenuItems.peek();
960b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                View menuItemButton = createMenuItemButton(mContext, menuItem);
961517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
962f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                // Adding additional start padding for the first button to even out button spacing.
963517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                if (isFirstItem) {
964f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                    menuItemButton.setPaddingRelative(
965f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            (int) (1.5 * menuItemButton.getPaddingStart()),
966517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuItemButton.getPaddingTop(),
967f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            menuItemButton.getPaddingEnd(),
968517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuItemButton.getPaddingBottom());
969517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    isFirstItem = false;
970517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
971517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
972f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                // Adding additional end padding for the last button to even out button spacing.
973517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                if (remainingMenuItems.size() == 1) {
974f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                    menuItemButton.setPaddingRelative(
975f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            menuItemButton.getPaddingStart(),
976517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuItemButton.getPaddingTop(),
977f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            (int) (1.5 * menuItemButton.getPaddingEnd()),
978517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuItemButton.getPaddingBottom());
979517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
980517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
981517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
982517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
983517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                if (menuItemButtonWidth <= availableWidth) {
984b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                    setButtonTagAndClickListener(menuItemButton, menuItem);
985517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentView.addView(menuItemButton);
986517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
987517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.width = menuItemButtonWidth;
988517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    menuItemButton.setLayoutParams(params);
989517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    availableWidth -= menuItemButtonWidth;
990517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    remainingMenuItems.pop();
991517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                } else {
992517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    if (mOpenOverflowButton == null) {
993b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        mOpenOverflowButton = LayoutInflater.from(mContext)
994517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                .inflate(R.layout.floating_popup_open_overflow_button, null);
995517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mOpenOverflowButton.setOnClickListener(new View.OnClickListener() {
996517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            @Override
997517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            public void onClick(View v) {
998517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                if (mOpenOverflowButton != null) {
999517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                    mOpenOverflow.run();
1000517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                }
1001517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            }
1002517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        });
1003517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
1004517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentView.addView(mOpenOverflowButton);
1005517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    break;
1006517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
1007517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
1008517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return remainingMenuItems;
1009517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1010517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1011517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) {
1012517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOnMenuItemClickListener = listener;
10130c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
10140c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1015517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public View getView() {
1016517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return mContentView;
10170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
10180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1019517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeIn(boolean animate) {
1020517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            viewFader.fadeIn(animate);
1021517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1022517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1023517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeOut(boolean animate) {
1024517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            viewFader.fadeOut(animate);
10250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
10260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
10270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
1028517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Returns how big this panel's view should be.
1029517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * This method should only be called when the view has not been attached to a parent
1030517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * otherwise it will throw an illegal state.
1031517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
1032517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public Size measure() throws IllegalStateException {
1033517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Preconditions.checkState(mContentView.getParent() == null);
1034517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
1035517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());
1036517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1037b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki
1038b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki        private void setButtonTagAndClickListener(View menuItemButton, MenuItem menuItem) {
1039b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            View button = menuItemButton;
1040b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            if (isIconOnlyMenuItem(menuItem)) {
1041b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                button = menuItemButton.findViewById(R.id.floating_toolbar_menu_item_image_button);
1042b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            }
1043b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            button.setTag(menuItem);
1044b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            button.setOnClickListener(mMenuItemButtonOnClickListener);
1045b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki        }
1046517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1047517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1048517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1049517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1050517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * A widget that holds the overflow items in the floating toolbar.
1051517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1052517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static final class FloatingToolbarOverflowPanel {
1053517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1054517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final LinearLayout mContentView;
1055517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewGroup mBackButtonContainer;
1056517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final View mBackButton;
1057517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ListView mListView;
1058f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private final TextView mListViewItemWidthCalculator;
1059517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewFader mViewFader;
1060517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Runnable mCloseOverflow;
1061517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1062517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
1063f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private int mOverflowWidth = 0;
1064ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        private int mSuggestedHeight;
1065517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1066517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
1067517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Initializes a floating toolbar popup overflow view panel.
10680c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         *
1069517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param context
1070517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param closeOverflow  The code that closes the toolbar popup's overflow.
1071517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
1072517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) {
1073517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mCloseOverflow = Preconditions.checkNotNull(closeOverflow);
1074ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            mSuggestedHeight = getScreenHeight(context);
1075517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1076517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView = new LinearLayout(context);
1077517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.setOrientation(LinearLayout.VERTICAL);
1078517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mViewFader = new ViewFader(mContentView);
1079517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1080517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mBackButton = LayoutInflater.from(context)
1081517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    .inflate(R.layout.floating_popup_close_overflow_button, null);
1082517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mBackButton.setOnClickListener(new View.OnClickListener() {
1083517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
1084517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                public void onClick(View v) {
1085517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mCloseOverflow.run();
1086517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
1087517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            });
1088517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mBackButtonContainer = new LinearLayout(context);
1089517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mBackButtonContainer.addView(mBackButton);
1090517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1091f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mListView = createOverflowListView();
1092517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
1093517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
1094517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
1095517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(position);
1096517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    if (mOnMenuItemClickListener != null) {
1097517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mOnMenuItemClickListener.onMenuItemClick(menuItem);
1098517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
1099517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
1100517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            });
1101517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1102517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.addView(mListView);
1103517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.addView(mBackButtonContainer);
1104f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki
1105f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mListViewItemWidthCalculator = createOverflowMenuItemButton(context);
1106f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mListViewItemWidthCalculator.setLayoutParams(new ViewGroup.LayoutParams(
1107f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
1108517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1109517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1110517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
1111517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Sets the menu items to be displayed in the overflow.
11120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
1113517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void setMenuItems(List<MenuItem> menuItems) {
1114517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            ArrayAdapter overflowListViewAdapter = (ArrayAdapter) mListView.getAdapter();
1115517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListViewAdapter.clear();
1116517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListViewAdapter.addAll(menuItems);
1117517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            setListViewHeight();
1118f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            setOverflowWidth();
1119517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1120517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1121517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) {
1122517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOnMenuItemClickListener = listener;
11230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
11240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
11250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
1126517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Notifies the overflow of the current direction in which the overflow will be opened.
11270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         *
1128517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param overflowDirection  {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_UP}
1129517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *   or {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_DOWN}.
11300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
1131517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void setOverflowDirection(int overflowDirection) {
1132517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.removeView(mBackButtonContainer);
1133517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int index = (overflowDirection == FloatingToolbarPopup.OVERFLOW_DIRECTION_UP)? 1 : 0;
1134517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.addView(mBackButtonContainer, index);
11350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
11360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1137ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        public void setSuggestedHeight(int height) {
1138ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            mSuggestedHeight = height;
1139ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            setListViewHeight();
1140ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki        }
1141ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki
11420c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
1143517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Returns the content view of the overflow.
1144517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
1145517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public View getView() {
1146517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return mContentView;
1147517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1148517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1149517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeIn(boolean animate) {
1150517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mViewFader.fadeIn(animate);
1151517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1152517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1153517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeOut(boolean animate) {
1154517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mViewFader.fadeOut(animate);
1155517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1156517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1157517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
1158517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Returns how big this panel's view should be.
1159517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * This method should only be called when the view has not been attached to a parent.
11600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         *
1161517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @throws IllegalStateException
11620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
1163517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public Size measure() {
1164517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Preconditions.checkState(mContentView.getParent() == null);
1165517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
1166517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());
1167517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1168517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1169517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void setListViewHeight() {
1170517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int itemHeight = getEstimatedToolbarHeight(mContentView.getContext());
1171517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int height = mListView.getAdapter().getCount() * itemHeight;
1172517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int maxHeight = mContentView.getContext().getResources().
1173ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                    getDimensionPixelSize(R.dimen.floating_toolbar_maximum_overflow_height);
1174ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            int minHeight = mContentView.getContext().getResources().
1175517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height);
1176ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            int availableHeight = mSuggestedHeight - (mSuggestedHeight % itemHeight)
1177ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                    - itemHeight;  // reserve space for the back button.
1178517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            ViewGroup.LayoutParams params = mListView.getLayoutParams();
1179ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            if (availableHeight >= minHeight) {
1180ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                params.height = Math.min(Math.min(availableHeight, maxHeight), height);
1181ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            } else {
1182ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki                params.height = Math.min(maxHeight, height);
1183ffebf68202311963c497f5793e17d7a075706fd6Abodunrinwa Toki            }
1184517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mListView.setLayoutParams(params);
11850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
1186517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1187f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private int setOverflowWidth() {
1188f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            for (int i = 0; i < mListView.getAdapter().getCount(); i++) {
1189f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(i);
1190f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                Preconditions.checkNotNull(menuItem);
1191f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                mListViewItemWidthCalculator.setText(menuItem.getTitle());
1192f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                mListViewItemWidthCalculator.measure(
1193f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                        MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
1194f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                mOverflowWidth = Math.max(
1195f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                        mListViewItemWidthCalculator.getMeasuredWidth(), mOverflowWidth);
1196f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            }
1197f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            return mOverflowWidth;
1198f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        }
1199f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki
1200f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private ListView createOverflowListView() {
1201f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            final Context context = mContentView.getContext();
1202517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final ListView overflowListView = new ListView(context);
1203517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListView.setLayoutParams(new ViewGroup.LayoutParams(
1204517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
1205517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListView.setDivider(null);
1206517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListView.setDividerHeight(0);
1207b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki
1208b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            final int viewTypeCount = 2;
1209b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            final int stringLabelViewType = 0;
1210b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            final int iconOnlyViewType = 1;
1211517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final ArrayAdapter overflowListViewAdapter =
1212517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    new ArrayAdapter<MenuItem>(context, 0) {
1213517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        @Override
1214b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        public int getViewTypeCount() {
1215b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            return viewTypeCount;
1216b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        }
1217b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki
1218b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        @Override
1219b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        public int getItemViewType(int position) {
1220b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            if (isIconOnlyMenuItem(getItem(position))) {
1221b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                                return iconOnlyViewType;
1222b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            }
1223b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            return stringLabelViewType;
1224b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        }
1225b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki
1226b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        @Override
1227517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        public View getView(int position, View convertView, ViewGroup parent) {
1228b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            if (getItemViewType(position) == iconOnlyViewType) {
1229b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                                return getIconOnlyView(position, convertView);
1230b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            }
1231b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            return getStringTitleView(position, convertView);
1232b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        }
1233b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki
1234b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        private View getStringTitleView(int position, View convertView) {
1235517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            TextView menuButton;
1236517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            if (convertView != null) {
1237517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                menuButton = (TextView) convertView;
1238517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            } else {
1239517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                menuButton = createOverflowMenuItemButton(context);
1240517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            }
1241517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            MenuItem menuItem = getItem(position);
1242517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuButton.setText(menuItem.getTitle());
1243517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuButton.setContentDescription(menuItem.getTitle());
1244f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            menuButton.setMinimumWidth(mOverflowWidth);
1245517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            return menuButton;
1246517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        }
1247b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki
1248b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        private View getIconOnlyView(int position, View convertView) {
1249b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            View menuButton;
1250b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            if (convertView != null) {
1251b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                                menuButton = convertView;
1252b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            } else {
1253b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                                menuButton = LayoutInflater.from(context).inflate(
1254b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                                        R.layout.floating_popup_overflow_image_list_item, null);
1255b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            }
1256b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            MenuItem menuItem = getItem(position);
1257b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            ((ImageView) menuButton
1258b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                                    .findViewById(R.id.floating_toolbar_menu_item_image_button))
1259b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                                    .setImageDrawable(menuItem.getIcon());
1260b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            menuButton.setMinimumWidth(mOverflowWidth);
1261b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                            return menuButton;
1262b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                        }
1263517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    };
1264517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListView.setAdapter(overflowListViewAdapter);
1265517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return overflowListView;
1266517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1267517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1268517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1269517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1270517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1271517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * A helper for fading in or out a view.
1272517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1273517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static final class ViewFader {
1274517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1275517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private static final int FADE_OUT_DURATION = 250;
1276517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private static final int FADE_IN_DURATION = 150;
1277517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1278517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final View mView;
1279517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ObjectAnimator mFadeOutAnimation;
1280517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ObjectAnimator mFadeInAnimation;
1281517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1282517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private ViewFader(View view) {
1283517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mView = Preconditions.checkNotNull(view);
1284517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mFadeOutAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0)
1285517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    .setDuration(FADE_OUT_DURATION);
1286517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mFadeInAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1)
1287517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    .setDuration(FADE_IN_DURATION);
1288517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1289517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1290517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeIn(boolean animate) {
1291b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            cancelFadeAnimations();
1292517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (animate) {
1293517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mFadeInAnimation.start();
1294517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            } else {
1295517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mView.setAlpha(1);
1296517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
1297517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1298517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1299517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeOut(boolean animate) {
1300b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            cancelFadeAnimations();
1301517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (animate) {
1302517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mFadeOutAnimation.start();
1303517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            } else {
1304517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mView.setAlpha(0);
1305517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
1306517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1307b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
1308b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private void cancelFadeAnimations() {
1309b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mFadeInAnimation.cancel();
1310b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mFadeOutAnimation.cancel();
1311b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        }
1312517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1313517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1314b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki    /**
1315b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki     * @return {@code true} if the menu item does not not have a string title but has an icon.
1316b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki     *   {@code false} otherwise.
1317b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki     */
1318b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki    private static boolean isIconOnlyMenuItem(MenuItem menuItem) {
1319b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki        if (TextUtils.isEmpty(menuItem.getTitle()) && menuItem.getIcon() != null) {
1320b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            return true;
1321b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki        }
1322b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki        return false;
1323b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki    }
1324517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1325517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1326517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Creates and returns a menu button for the specified menu item.
1327517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1328b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki    private static View createMenuItemButton(Context context, MenuItem menuItem) {
1329b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki        if (isIconOnlyMenuItem(menuItem)) {
1330b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            View imageMenuItemButton = LayoutInflater.from(context)
1331b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                    .inflate(R.layout.floating_popup_menu_image_button, null);
1332b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            ((ImageButton) imageMenuItemButton
1333b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                    .findViewById(R.id.floating_toolbar_menu_item_image_button))
1334b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki                    .setImageDrawable(menuItem.getIcon());
1335b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki            return imageMenuItemButton;
1336b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki        }
1337b21562c4655cb8dfb73819b68b7fc8eeeab40dacAbodunrinwa Toki
1338517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        Button menuItemButton = (Button) LayoutInflater.from(context)
1339517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                .inflate(R.layout.floating_popup_menu_button, null);
1340517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        menuItemButton.setText(menuItem.getTitle());
1341517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        menuItemButton.setContentDescription(menuItem.getTitle());
1342517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return menuItemButton;
1343517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1344517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1345517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1346517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Creates and returns a styled floating toolbar overflow list view item.
1347517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1348517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static TextView createOverflowMenuItemButton(Context context) {
1349517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return (TextView) LayoutInflater.from(context)
1350517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                .inflate(R.layout.floating_popup_overflow_list_item, null);
1351517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1352517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1353517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static ViewGroup createContentContainer(Context context) {
1354517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return (ViewGroup) LayoutInflater.from(context)
1355517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                .inflate(R.layout.floating_popup_container, null);
1356517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1357517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1358517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static PopupWindow createPopupWindow(View content) {
1359517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        ViewGroup popupContentHolder = new LinearLayout(content.getContext());
1360517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        PopupWindow popupWindow = new PopupWindow(popupContentHolder);
1361103d48ec09cbaeedf28b66425cde9198f767e0d5Abodunrinwa Toki        popupWindow.setWindowLayoutType(
1362103d48ec09cbaeedf28b66425cde9198f767e0d5Abodunrinwa Toki                WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
1363517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        popupWindow.setAnimationStyle(0);
1364517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
1365517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        content.setLayoutParams(new ViewGroup.LayoutParams(
1366517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
1367517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        popupContentHolder.addView(content);
1368517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return popupWindow;
1369517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1370517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1371517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
13727aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki     * Creates an "appear" animation for the specified view.
1373517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     *
1374517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * @param view  The view to animate
1375517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
13767aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki    private static AnimatorSet createEnterAnimation(View view) {
13777aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki        AnimatorSet animation =  new AnimatorSet();
13787aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki        animation.playTogether(
13797aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki                ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(200),
13806c5ac8e9e6b4b06c460cd2231cdeb93b373efe5dAbodunrinwa Toki                // Make sure that view.x is always fixed throughout the duration of this animation.
13816cb5cc19d467251d2e1e28791bf070f4ea6a2eedAbodunrinwa Toki                ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX()));
13827aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki        animation.setStartDelay(50);
13837aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki        return animation;
1384517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1385517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1386517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
13877aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki     * Creates a "disappear" animation for the specified view.
1388517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     *
1389517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * @param view  The view to animate
1390cdffaa4c5af71b4bd0c99a98d411ee3883ec4733Abodunrinwa Toki     * @param startDelay  The start delay of the animation
1391517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * @param listener  The animation listener
1392517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
13937aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki    private static AnimatorSet createExitAnimation(
1394cdffaa4c5af71b4bd0c99a98d411ee3883ec4733Abodunrinwa Toki            View view, int startDelay, Animator.AnimatorListener listener) {
13957aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki        AnimatorSet animation =  new AnimatorSet();
13967aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki        animation.playTogether(
13977aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki                ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(200));
13987aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki        animation.setStartDelay(startDelay);
13997aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki        animation.addListener(listener);
14007aa6d0a4b1ec7f75335348a86284d3773cc72f91Abodunrinwa Toki        return animation;
1401517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1402517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1403517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getEstimatedToolbarHeight(Context context) {
1404517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return context.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_height);
1405517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1406517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1407517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getEstimatedOpenOverflowButtonWidth(Context context) {
1408517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return context.getResources()
1409517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                .getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_minimum_width);
1410517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1411517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1412517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getAdjustedToolbarWidth(Context context, int width) {
1413c0fa6bd7ac8fa8f138c62d734d276e55d600bb6bAbodunrinwa Toki        int maximumWidth = getScreenWidth(context) - 2 * context.getResources()
1414c0fa6bd7ac8fa8f138c62d734d276e55d600bb6bAbodunrinwa Toki                .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
1415c0fa6bd7ac8fa8f138c62d734d276e55d600bb6bAbodunrinwa Toki
1416c0fa6bd7ac8fa8f138c62d734d276e55d600bb6bAbodunrinwa Toki        if (width <= 0 || width > maximumWidth) {
1417c0fa6bd7ac8fa8f138c62d734d276e55d600bb6bAbodunrinwa Toki            int defaultWidth = context.getResources()
1418c0fa6bd7ac8fa8f138c62d734d276e55d600bb6bAbodunrinwa Toki                    .getDimensionPixelSize(R.dimen.floating_toolbar_preferred_width);
1419c0fa6bd7ac8fa8f138c62d734d276e55d600bb6bAbodunrinwa Toki            width = Math.min(defaultWidth, maximumWidth);
1420517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1421517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return width;
1422517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1423517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1424517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1425517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Returns the device's screen width.
1426517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1427517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getScreenWidth(Context context) {
1428517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return context.getResources().getDisplayMetrics().widthPixels;
1429517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1430517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1431517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1432517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Returns the device's screen height.
1433517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1434517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getScreenHeight(Context context) {
1435517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return context.getResources().getDisplayMetrics().heightPixels;
1436517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
14370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki}
1438