FloatingToolbar.java revision d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1
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;
29517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.util.Size;
300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Gravity;
310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.LayoutInflater;
320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Menu;
330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.MenuItem;
340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.View;
350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.View.MeasureSpec;
360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.ViewGroup;
37517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.ViewTreeObserver;
380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.view.Window;
39517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.WindowManager;
40517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.Animation;
41517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.AnimationSet;
42517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.view.animation.Transformation;
43517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.AdapterView;
44517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.ArrayAdapter;
450c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.Button;
460c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.ImageButton;
470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.LinearLayout;
48517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.ListView;
490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport android.widget.PopupWindow;
50517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport android.widget.TextView;
510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.ArrayList;
530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.LinkedList;
540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokiimport java.util.List;
550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
56517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport com.android.internal.R;
57517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Tokiimport com.android.internal.util.Preconditions;
58517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki/**
600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * A floating toolbar for showing contextual menu items.
610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * This view shows as many menu item buttons as can fit in the horizontal toolbar and the
620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * the remaining menu items in a vertical overflow view when the overflow button is clicked.
630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki * The horizontal toolbar morphs into the vertical overflow view.
640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki */
650c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Tokipublic final class FloatingToolbar {
660c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
67517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    // This class is responsible for the public API of the floating toolbar.
68517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    // It delegates rendering operations to the FloatingToolbarPopup.
69517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER =
710c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            new MenuItem.OnMenuItemClickListener() {
720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                @Override
730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                public boolean onMenuItemClick(MenuItem item) {
740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    return false;
750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                }
760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            };
770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private final Context mContext;
790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private final FloatingToolbarPopup mPopup;
800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
810c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private final Rect mContentRect = new Rect();
820c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private final Point mCoordinates = new Point();
830c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
840c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private Menu mMenu;
850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>();
860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
870c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
880c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private int mSuggestedWidth;
89517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private boolean mWidthChanged = true;
90517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private int mOverflowDirection;
910c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Initializes a floating toolbar.
940c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
950c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar(Context context, Window window) {
960c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mContext = Preconditions.checkNotNull(context);
97517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        mPopup = new FloatingToolbarPopup(window.getDecorView());
980c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
990c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1000c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1010c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Sets the menu to be shown in this floating toolbar.
1020c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
1030c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * toolbar.
1040c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1050c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar setMenu(Menu menu) {
1060c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mMenu = Preconditions.checkNotNull(menu);
1070c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1080c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1090c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1100c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1117270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Sets the custom listener for invocation of menu items in this floating toolbar.
1120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1130c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar setOnMenuItemClickListener(
1140c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            MenuItem.OnMenuItemClickListener menuItemClickListener) {
1150c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        if (menuItemClickListener != null) {
1160c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mMenuItemClickListener = menuItemClickListener;
1170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        } else {
1180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
1190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
1200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Sets the content rectangle. This is the area of the interesting content that this toolbar
1250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * should avoid obstructing.
1260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
1270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * toolbar.
1280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar setContentRect(Rect rect) {
1300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mContentRect.set(Preconditions.checkNotNull(rect));
1310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Sets the suggested width of this floating toolbar.
1360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * The actual width will be about this size but there are no guarantees that it will be exactly
1370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * the suggested width.
1380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * NOTE: Call {@link #updateLayout()} or {@link #show()} to effect visual changes to the
1390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * toolbar.
1400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar setSuggestedWidth(int suggestedWidth) {
142517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        // Check if there's been a substantial width spec change.
143517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        int difference = Math.abs(suggestedWidth - mSuggestedWidth);
144517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        mWidthChanged = difference > (mSuggestedWidth * 0.2);
145517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1460c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mSuggestedWidth = suggestedWidth;
1470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Shows this floating toolbar.
1520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar show() {
1540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
155517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        if (!isCurrentlyShowing(menuItems) || mWidthChanged) {
1560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mPopup.dismiss();
157517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth);
1580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mShowingTitles = getMenuItemTitles(menuItems);
1590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
1600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        refreshCoordinates();
161517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        mPopup.setOverflowDirection(mOverflowDirection);
1620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mPopup.updateCoordinates(mCoordinates.x, mCoordinates.y);
1630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        if (!mPopup.isShowing()) {
1640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mPopup.show(mCoordinates.x, mCoordinates.y);
1650c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
166517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        mWidthChanged = false;
1670c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1680c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1690c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1710c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Updates this floating toolbar to reflect recent position and view updates.
1720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * NOTE: This method is a no-op if the toolbar isn't showing.
1730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public FloatingToolbar updateLayout() {
1750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        if (mPopup.isShowing()) {
1760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            // show() performs all the logic we need here.
1770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            show();
1780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
1790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return this;
1800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1810c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1820c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1830c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Dismisses this floating toolbar.
1840c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
1850c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public void dismiss() {
1860c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mPopup.dismiss();
1870c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
1880c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
1890c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
1907270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Hides this floating toolbar. This is a no-op if the toolbar is not showing.
1917270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Use {@link #isHidden()} to distinguish between a hidden and a dismissed toolbar.
1927270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     */
1937270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    public void hide() {
1947270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        mPopup.hide();
1957270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    }
1967270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
1977270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    /**
1987270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Returns {@code true} if this toolbar is currently showing. {@code false} otherwise.
1990c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
2000c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    public boolean isShowing() {
2010c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return mPopup.isShowing();
2020c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
2030c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2040c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
2057270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     * Returns {@code true} if this toolbar is currently hidden. {@code false} otherwise.
2067270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki     */
2077270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    public boolean isHidden() {
2087270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        return mPopup.isHidden();
2097270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    }
2107270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
2117270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki    /**
2120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}.
2130c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
2140c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private void refreshCoordinates() {
215517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        int x = mContentRect.centerX() - mPopup.getWidth() / 2;
2160c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        int y;
217517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        if (mContentRect.top > mPopup.getHeight()) {
218517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            y = mContentRect.top - mPopup.getHeight();
219517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP;
220f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        } else if (mContentRect.top > mPopup.getToolbarHeightWithVerticalMargin()) {
221f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            y = mContentRect.top - mPopup.getToolbarHeightWithVerticalMargin();
222517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
2230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        } else {
2240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            y = mContentRect.bottom;
225517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
2260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
2270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        mCoordinates.set(x, y);
2280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
2290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
231517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Returns true if this floating toolbar is currently showing the specified menu items.
2320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
233517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private boolean isCurrentlyShowing(List<MenuItem> menuItems) {
234517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return mShowingTitles.equals(getMenuItemTitles(menuItems));
2350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
2360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
2380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * Returns the visible and enabled menu items in the specified menu.
2390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     * This method is recursive.
2400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
2410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private List<MenuItem> getVisibleAndEnabledMenuItems(Menu menu) {
2420c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        List<MenuItem> menuItems = new ArrayList<MenuItem>();
2430c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        for (int i = 0; (menu != null) && (i < menu.size()); i++) {
2440c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            MenuItem menuItem = menu.getItem(i);
2450c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            if (menuItem.isVisible() && menuItem.isEnabled()) {
2460c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                Menu subMenu = menuItem.getSubMenu();
2470c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                if (subMenu != null) {
2480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    menuItems.addAll(getVisibleAndEnabledMenuItems(subMenu));
2490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                } else {
2500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    menuItems.add(menuItem);
2510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                }
2520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            }
2530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
2540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return menuItems;
2550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
2560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    private List<CharSequence> getMenuItemTitles(List<MenuItem> menuItems) {
2580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        List<CharSequence> titles = new ArrayList<CharSequence>();
2590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        for (MenuItem menuItem : menuItems) {
2600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            titles.add(menuItem.getTitle());
2610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
2620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        return titles;
2630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
2640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2650c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
2660c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    /**
267517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * A popup window used by the floating toolbar.
268517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     *
269517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * This class is responsible for the rendering/animation of the floating toolbar.
270517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * It can hold one of 2 panels (i.e. main panel and overflow panel) at a time.
271517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * It delegates specific panel functionality to the appropriate panel.
2720c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki     */
273517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static final class FloatingToolbarPopup {
2740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
275517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public static final int OVERFLOW_DIRECTION_UP = 0;
276517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public static final int OVERFLOW_DIRECTION_DOWN = 1;
2770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
278517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final View mParent;
279517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final PopupWindow mPopupWindow;
280517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewGroup mContentContainer;
281f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private final int mMarginHorizontal;
282f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private final int mMarginVertical;
2830c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
284517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Animation.AnimationListener mOnOverflowOpened =
285517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                new Animation.AnimationListener() {
286517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
287517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationStart(Animation animation) {}
2880c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
289517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
290517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationEnd(Animation animation) {
291b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                        setOverflowPanelAsContent();
292517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mOverflowPanel.fadeIn(true);
293517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
2940c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
295517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
296517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationRepeat(Animation animation) {}
297517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                };
298517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Animation.AnimationListener mOnOverflowClosed =
299517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                new Animation.AnimationListener() {
300517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
301517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationStart(Animation animation) {}
3020c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
303517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
304517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationEnd(Animation animation) {
305b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                        setMainPanelAsContent();
306517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mMainPanel.fadeIn(true);
307517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
3080c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
3090c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    @Override
310517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onAnimationRepeat(Animation animation) {
3110c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                    }
3120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                };
3137270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private final AnimatorSet mShowAnimation;
3147270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private final AnimatorSet mDismissAnimation;
3157270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private final AnimatorSet mHideAnimation;
316b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private final AnimationSet mOpenOverflowAnimation = new AnimationSet(true) {
317b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            @Override
318b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            public void cancel() {
319b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                if (hasStarted() && !hasEnded()) {
320b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    super.cancel();
321b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    setOverflowPanelAsContent();
322b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                }
323b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            }
324b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        };
325b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private final AnimationSet mCloseOverflowAnimation = new AnimationSet(true) {
326b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            @Override
327b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            public void cancel() {
328b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                if (hasStarted() && !hasEnded()) {
329b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    super.cancel();
330b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    setMainPanelAsContent();
331b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                }
332b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            }
333b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        };
3340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
335517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Runnable mOpenOverflow = new Runnable() {
336517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            @Override
337517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            public void run() {
338517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                openOverflow();
339517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
340517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        };
341517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Runnable mCloseOverflow = new Runnable() {
342517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            @Override
343517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            public void run() {
344517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                closeOverflow();
345517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
346517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        };
347517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
348517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Region mTouchableRegion = new Region();
349d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki        private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
350d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                new ViewTreeObserver.OnComputeInternalInsetsListener() {
351d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                    public void onComputeInternalInsets(
352d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                            ViewTreeObserver.InternalInsetsInfo info) {
353d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                        info.contentInsets.setEmpty();
354d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                        info.visibleInsets.setEmpty();
355d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                        info.touchableRegion.set(mTouchableRegion);
356d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                        info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo
357d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                                .TOUCHABLE_INSETS_REGION);
358d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                    }
359d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                };
360517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
3617270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private boolean mDismissed = true; // tracks whether this popup is dismissed or dismissing.
3627270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private boolean mHidden; // tracks whether this popup is hidden or hiding.
3630c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
364517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private FloatingToolbarOverflowPanel mOverflowPanel;
365517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private FloatingToolbarMainPanel mMainPanel;
366517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private int mOverflowDirection;
367517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
3680c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
369517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Initializes a new floating toolbar popup.
3700c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         *
371517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param parent  A parent view to get the {@link android.view.View#getWindowToken()} token
372517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *      from.
3730c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
3740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public FloatingToolbarPopup(View parent) {
3750c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mParent = Preconditions.checkNotNull(parent);
3760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mContentContainer = createContentContainer(parent.getContext());
3770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            mPopupWindow = createPopupWindow(mContentContainer);
3787270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mShowAnimation = createGrowFadeInFromBottom(mContentContainer);
3797270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mDismissAnimation = createShrinkFadeOutFromBottomAnimation(
380517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer,
381517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    new AnimatorListenerAdapter() {
382517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        @Override
383517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        public void onAnimationEnd(Animator animation) {
384517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            mPopupWindow.dismiss();
385b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                            mContentContainer.removeAllViews();
386517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        }
387517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    });
3887270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHideAnimation = createShrinkFadeOutFromBottomAnimation(
3897270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                    mContentContainer,
3907270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                    new AnimatorListenerAdapter() {
3917270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                        @Override
3927270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                        public void onAnimationEnd(Animator animation) {
3937270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                            mPopupWindow.dismiss();
3947270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                        }
3957270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                    });
396f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mMarginHorizontal = parent.getResources()
397f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                    .getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin);
398f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mMarginVertical = parent.getResources()
399f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                    .getDimensionPixelSize(R.dimen.floating_toolbar_vertical_margin);
400517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
401517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
402517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
403517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Lays out buttons for the specified menu items.
404517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
405517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void layoutMenuItems(List<MenuItem> menuItems,
406517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                MenuItem.OnMenuItemClickListener menuItemClickListener, int suggestedWidth) {
407517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentContainer.removeAllViews();
408517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (mMainPanel == null) {
409517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow);
410517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
411517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            List<MenuItem> overflowMenuItems =
412517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mMainPanel.layoutMenuItems(menuItems, suggestedWidth);
413517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mMainPanel.setOnMenuItemClickListener(menuItemClickListener);
414517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (!overflowMenuItems.isEmpty()) {
415517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                if (mOverflowPanel == null) {
416517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mOverflowPanel =
417517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            new FloatingToolbarOverflowPanel(mParent.getContext(), mCloseOverflow);
418517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
419517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mOverflowPanel.setMenuItems(overflowMenuItems);
420517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mOverflowPanel.setOnMenuItemClickListener(menuItemClickListener);
421517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
422517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            updatePopupSize();
4230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
4240c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
4260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Shows this popup at the specified coordinates.
4270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
4280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
4290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public void show(int x, int y) {
4300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            if (isShowing()) {
4310c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                return;
4320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            }
4330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4347270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHidden = false;
4357270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mDismissed = false;
436b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            cancelAllAnimations();
437b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // Make sure a panel is set as the content.
438b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            if (mContentContainer.getChildCount() == 0) {
439b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                setMainPanelAsContent();
440b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            }
441517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            preparePopupContent();
442b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // If we're yet to show the popup, set the container visibility to zero.
443b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // The "show" animation will make this visible.
444b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setAlpha(0);
445517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y);
446d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki            setTouchableSurfaceInsetsComputer();
4477270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            runShowAnimation();
4480c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
4490c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4500c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
4510c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
4520c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
4530c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public void dismiss() {
4540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            if (!isShowing()) {
4550c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki                return;
4560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            }
4570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4587270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHidden = false;
4597270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mDismissed = true;
4607270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            runDismissAnimation();
4617270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            setZeroTouchableSurface();
4627270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        }
4637270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
4647270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        /**
4657270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Hides this popup. This is a no-op if this popup is not showing.
4667270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup.
4677270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         */
4687270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        public void hide() {
4697270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            if (!isShowing()) {
4707270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki                return;
4717270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            }
4727270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
4737270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHidden = true;
4747270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            runHideAnimation();
475517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            setZeroTouchableSurface();
4760c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
4770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
4790c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
4800c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
4810c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public boolean isShowing() {
4827270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            return mPopupWindow.isShowing() && !mDismissed && !mHidden;
4837270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        }
4847270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
4857270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        /**
4867270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Returns {@code true} if this popup is currently hidden. {@code false} otherwise.
4877270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         */
4887270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        public boolean isHidden() {
4897270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            return mHidden;
4900c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
4910c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
4920c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
4930c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Updates the coordinates of this popup.
4940c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
4957270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * This is a no-op if this popup is not showing.
4960c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
4970c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public void updateCoordinates(int x, int y) {
4987270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            if (!isShowing()) {
499517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                return;
5000c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            }
501517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
502b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            cancelAllAnimations();
503517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            preparePopupContent();
504517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mPopupWindow.update(x, y, getWidth(), getHeight());
5050c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5060c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5070c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
508517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Sets the direction in which the overflow will open. i.e. up or down.
509517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *
510517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param overflowDirection Either {@link #OVERFLOW_DIRECTION_UP}
511517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *   or {@link #OVERFLOW_DIRECTION_DOWN}.
5120c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
513517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void setOverflowDirection(int overflowDirection) {
514517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOverflowDirection = overflowDirection;
515517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (mOverflowPanel != null) {
516517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mOverflowPanel.setOverflowDirection(mOverflowDirection);
517517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
5180c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5190c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5200c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5210c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Returns the width of this popup.
5220c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5230c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public int getWidth() {
524517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return mPopupWindow.getWidth();
5250c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5260c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5270c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Returns the height of this popup.
5290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public int getHeight() {
531517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return mPopupWindow.getHeight();
5320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         * Returns the context this popup is running in.
5360c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5370c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        public Context getContext() {
5380c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki            return mContentContainer.getContext();
5390c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
541f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        int getToolbarHeightWithVerticalMargin() {
542f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            return getEstimatedToolbarHeight(mParent.getContext()) + mMarginVertical * 2;
543f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        }
544f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki
5450c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5467270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Performs the "show" animation on the floating popup.
5477270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         */
5487270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private void runShowAnimation() {
5497270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mShowAnimation.start();
5507270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        }
5517270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki
5527270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        /**
5537270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Performs the "dismiss" animation on the floating popup.
5540c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5557270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private void runDismissAnimation() {
5567270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mDismissAnimation.start();
5570c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5580c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
5590c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
5607270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki         * Performs the "hide" animation on the floating popup.
5610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
5627270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki        private void runHideAnimation() {
5637270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHideAnimation.start();
5640c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
5650c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
566b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private void cancelAllAnimations() {
567b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mShowAnimation.cancel();
5687270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mDismissAnimation.cancel();
5697270d07aab00c30c7f339963d3e9312456a2462eAbodunrinwa Toki            mHideAnimation.cancel();
570b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.cancel();
571b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.cancel();
572517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
573517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
574517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
575517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Opens the floating toolbar overflow.
576517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * This method should not be called if menu items have not been laid out with
577b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}.
578517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *
579517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @throws IllegalStateException if called when menu items have not been laid out.
580517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
581517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void openOverflow() {
582b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkState(mMainPanel != null);
583b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkState(mOverflowPanel != null);
584517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
585517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mMainPanel.fadeOut(true);
586517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Size overflowPanelSize = mOverflowPanel.measure();
587f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            final int targetWidth = overflowPanelSize.getWidth();
588517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int targetHeight = overflowPanelSize.getHeight();
589517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final boolean morphUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP);
590517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int startWidth = mContentContainer.getWidth();
591517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int startHeight = mContentContainer.getHeight();
592517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final float startY = mContentContainer.getY();
593517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final float right = mContentContainer.getX() + mContentContainer.getWidth();
594517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Animation widthAnimation = new Animation() {
595517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
596517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                protected void applyTransformation(float interpolatedTime, Transformation t) {
597517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
598517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
599517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.width = startWidth + deltaWidth;
600517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setLayoutParams(params);
601517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setX(right - mContentContainer.getWidth());
602517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
603517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            };
604517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Animation heightAnimation = new Animation() {
605517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
606517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                protected void applyTransformation(float interpolatedTime, Transformation t) {
607517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
608517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
609517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.height = startHeight + deltaHeight;
610517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setLayoutParams(params);
611517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    if (morphUpwards) {
612517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        float y = startY - (mContentContainer.getHeight() - startHeight);
613517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mContentContainer.setY(y);
614517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
615517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
616517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            };
617517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            widthAnimation.setDuration(240);
618517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            heightAnimation.setDuration(180);
619517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            heightAnimation.setStartOffset(60);
620b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.getAnimations().clear();
621b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.setAnimationListener(mOnOverflowOpened);
622b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.addAnimation(widthAnimation);
623b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mOpenOverflowAnimation.addAnimation(heightAnimation);
624b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.startAnimation(mOpenOverflowAnimation);
625517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
626517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
627517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
628517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Opens the floating toolbar overflow.
629517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * This method should not be called if menu items have not been laid out with
630517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}.
631517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *
632b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * @throws IllegalStateException if called when menu items have not been laid out.
633517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
634517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void closeOverflow() {
635b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkState(mMainPanel != null);
636b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkState(mOverflowPanel != null);
637517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
638517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOverflowPanel.fadeOut(true);
639517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Size mainPanelSize = mMainPanel.measure();
640517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int targetWidth = mainPanelSize.getWidth();
641517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int targetHeight = mainPanelSize.getHeight();
642517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int startWidth = mContentContainer.getWidth();
643517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int startHeight = mContentContainer.getHeight();
644517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final float right = mContentContainer.getX() + mContentContainer.getWidth();
645517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final float bottom = mContentContainer.getY() + mContentContainer.getHeight();
646517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final boolean morphedUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP);
647517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Animation widthAnimation = new Animation() {
648517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
649517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                protected void applyTransformation(float interpolatedTime, Transformation t) {
650517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
651517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
652517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.width = startWidth + deltaWidth;
653517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setLayoutParams(params);
654517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setX(right - mContentContainer.getWidth());
655517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
656517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            };
657517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Animation heightAnimation = new Animation() {
658517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
659517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                protected void applyTransformation(float interpolatedTime, Transformation t) {
660517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
661517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
662517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.height = startHeight + deltaHeight;
663517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentContainer.setLayoutParams(params);
664517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    if (morphedUpwards) {
665517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mContentContainer.setY(bottom - mContentContainer.getHeight());
666517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
667517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
668517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            };
669517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            widthAnimation.setDuration(150);
670517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            widthAnimation.setStartOffset(150);
671517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            heightAnimation.setDuration(210);
672b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.getAnimations().clear();
673b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.setAnimationListener(mOnOverflowClosed);
674b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.addAnimation(widthAnimation);
675b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mCloseOverflowAnimation.addAnimation(heightAnimation);
676b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.startAnimation(mCloseOverflowAnimation);
677517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
678517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
679517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
680517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Prepares the content container for show and update calls.
681517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
682517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void preparePopupContent() {
683b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // Reset visibility.
684b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            if (mMainPanel != null) {
685b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                mMainPanel.fadeIn(false);
686517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
687517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (mOverflowPanel != null) {
688517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mOverflowPanel.fadeIn(false);
689517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
690517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
691b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // Reset position.
692b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            if (mMainPanel != null
693b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    && mContentContainer.getChildAt(0) == mMainPanel.getView()) {
694b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                positionMainPanel();
695517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
696b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            if (mOverflowPanel != null
697b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    && mContentContainer.getChildAt(0) == mOverflowPanel.getView()) {
698b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                positionOverflowPanel();
699517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
700517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
701517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
702517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
703517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Sets the current content to be the main view panel.
704517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
705517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void setMainPanelAsContent() {
706b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // This should never be called if the main panel has not been initialized.
707b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkNotNull(mMainPanel);
708517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentContainer.removeAllViews();
709517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Size mainPanelSize = mMainPanel.measure();
710517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
711517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            params.width = mainPanelSize.getWidth();
712517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            params.height = mainPanelSize.getHeight();
713517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentContainer.setLayoutParams(params);
714517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentContainer.addView(mMainPanel.getView());
715b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            setContentAreaAsTouchableSurface();
716b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        }
717b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
718b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        /**
719b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * Sets the current content to be the overflow view panel.
720b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         */
721b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private void setOverflowPanelAsContent() {
722b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            // This should never be called if the overflow panel has not been initialized.
723b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkNotNull(mOverflowPanel);
724b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.removeAllViews();
725b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Size overflowPanelSize = mOverflowPanel.measure();
726b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
727b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            params.width = overflowPanelSize.getWidth();
728b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            params.height = overflowPanelSize.getHeight();
729b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setLayoutParams(params);
730b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.addView(mOverflowPanel.getView());
731b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            setContentAreaAsTouchableSurface();
732b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        }
733b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
734b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        /**
735b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * Places the main view panel at the appropriate resting coordinates.
736b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         */
737b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private void positionMainPanel() {
738b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkNotNull(mMainPanel);
739b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            float x = mPopupWindow.getWidth()
740b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    - (mMainPanel.getView().getMeasuredWidth() + mMarginHorizontal);
741b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setX(x);
742b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
743b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            float y = mMarginVertical;
744b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            if  (mOverflowDirection == OVERFLOW_DIRECTION_UP) {
745b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                y = getHeight()
746b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                        - (mMainPanel.getView().getMeasuredHeight() + mMarginVertical);
747b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            }
748b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setY(y);
749b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            setContentAreaAsTouchableSurface();
750b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        }
751b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
752b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        /**
753b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         * Places the main view panel at the appropriate resting coordinates.
754b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki         */
755b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private void positionOverflowPanel() {
756b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            Preconditions.checkNotNull(mOverflowPanel);
757b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            float x = mPopupWindow.getWidth()
758b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki                    - (mOverflowPanel.getView().getMeasuredWidth() + mMarginHorizontal);
759b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setX(x);
760b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mContentContainer.setY(mMarginVertical);
761b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            setContentAreaAsTouchableSurface();
762517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
763517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
764517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void updatePopupSize() {
765517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int width = 0;
766517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int height = 0;
767517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (mMainPanel != null) {
768517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                Size mainPanelSize = mMainPanel.measure();
769517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                width = mainPanelSize.getWidth();
770517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                height = mainPanelSize.getHeight();
771517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
772517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (mOverflowPanel != null) {
773517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                Size overflowPanelSize = mOverflowPanel.measure();
774517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                width = Math.max(width, overflowPanelSize.getWidth());
775517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                height = Math.max(height, overflowPanelSize.getHeight());
776517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
777f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mPopupWindow.setWidth(width + mMarginHorizontal * 2);
778f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mPopupWindow.setHeight(height + mMarginVertical * 2);
779517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
780517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
781517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
782517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Sets the touchable region of this popup to be zero. This means that all touch events on
783517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * this popup will go through to the surface behind it.
784517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
785517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void setZeroTouchableSurface() {
786517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mTouchableRegion.setEmpty();
787517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
788517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
789517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
790517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Sets the touchable region of this popup to be the area occupied by its content.
791517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
792517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void setContentAreaAsTouchableSurface() {
793517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (!mPopupWindow.isShowing()) {
794517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
795517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
796517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int width = mContentContainer.getMeasuredWidth();
797517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int height = mContentContainer.getMeasuredHeight();
798517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mTouchableRegion.set(
799517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    (int) mContentContainer.getX(),
800517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    (int) mContentContainer.getY(),
801517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    (int) mContentContainer.getX() + width,
802517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    (int) mContentContainer.getY() + height);
803517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
804d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki
805d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki        /**
806d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki         * Make the touchable area of this popup be the area specified by mTouchableRegion.
807d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki         * This should be called after the popup window has been dismissed (dismiss/hide)
808d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki         * and is probably being re-shown with a new content root view.
809d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki         */
810d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki        private void setTouchableSurfaceInsetsComputer() {
811d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki            ViewTreeObserver viewTreeObserver = mPopupWindow.getContentView()
812d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                    .getRootView()
813d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki                    .getViewTreeObserver();
814d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki            viewTreeObserver.removeOnComputeInternalInsetsListener(mInsetsComputer);
815d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki            viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer);
816d5358ffbee845ecb2ab3e1ebdfec3823104c0dd1Abodunrinwa Toki        }
817517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
818517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
819517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
820517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * A widget that holds the primary menu items in the floating toolbar.
821517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
822517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static final class FloatingToolbarMainPanel {
823517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
824517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Context mContext;
825517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewGroup mContentView;
826517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final View.OnClickListener mMenuItemButtonOnClickListener =
827517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                new View.OnClickListener() {
828517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    @Override
829517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    public void onClick(View v) {
830517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        if (v.getTag() instanceof MenuItem) {
831517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            if (mOnMenuItemClickListener != null) {
832517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                mOnMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag());
833517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            }
834517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        }
835517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
836517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                };
837517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewFader viewFader;
838517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Runnable mOpenOverflow;
839517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
840517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private View mOpenOverflowButton;
841517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
842517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
843517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
844517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Initializes a floating toolbar popup main view panel.
845517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *
846517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param context
847517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param openOverflow  The code that opens the toolbar popup overflow.
848517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
849517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public FloatingToolbarMainPanel(Context context, Runnable openOverflow) {
850517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContext = Preconditions.checkNotNull(context);
851517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView = new LinearLayout(context);
852517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            viewFader = new ViewFader(mContentView);
853517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOpenOverflow = Preconditions.checkNotNull(openOverflow);
854517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
855517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
8560c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
857517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Fits as many menu items in the main panel and returns a list of the menu items that
858517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * were not fit in.
859517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *
860517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @return The menu items that are not included in this main panel.
8610c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
862517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int suggestedWidth) {
863517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final int toolbarWidth = getAdjustedToolbarWidth(mContext, suggestedWidth)
864517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    // Reserve space for the "open overflow" button.
865517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    - getEstimatedOpenOverflowButtonWidth(mContext);
866517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
867517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int availableWidth = toolbarWidth;
868517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
869517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
870517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.removeAllViews();
871517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
872517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            boolean isFirstItem = true;
873517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            while (!remainingMenuItems.isEmpty()) {
874517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                final MenuItem menuItem = remainingMenuItems.peek();
875517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                Button menuItemButton = createMenuItemButton(mContext, menuItem);
876517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
877f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                // Adding additional start padding for the first button to even out button spacing.
878517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                if (isFirstItem) {
879f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                    menuItemButton.setPaddingRelative(
880f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            (int) (1.5 * menuItemButton.getPaddingStart()),
881517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuItemButton.getPaddingTop(),
882f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            menuItemButton.getPaddingEnd(),
883517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuItemButton.getPaddingBottom());
884517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    isFirstItem = false;
885517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
886517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
887f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                // Adding additional end padding for the last button to even out button spacing.
888517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                if (remainingMenuItems.size() == 1) {
889f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                    menuItemButton.setPaddingRelative(
890f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            menuItemButton.getPaddingStart(),
891517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuItemButton.getPaddingTop(),
892f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            (int) (1.5 * menuItemButton.getPaddingEnd()),
893517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuItemButton.getPaddingBottom());
894517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
895517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
896517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
897517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
898517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                if (menuItemButtonWidth <= availableWidth) {
899517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    menuItemButton.setTag(menuItem);
900517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener);
901517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentView.addView(menuItemButton);
902517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
903517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    params.width = menuItemButtonWidth;
904517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    menuItemButton.setLayoutParams(params);
905517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    availableWidth -= menuItemButtonWidth;
906517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    remainingMenuItems.pop();
907517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                } else {
908517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    if (mOpenOverflowButton == null) {
909517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mOpenOverflowButton = (ImageButton) LayoutInflater.from(mContext)
910517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                .inflate(R.layout.floating_popup_open_overflow_button, null);
911517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mOpenOverflowButton.setOnClickListener(new View.OnClickListener() {
912517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            @Override
913517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            public void onClick(View v) {
914517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                if (mOpenOverflowButton != null) {
915517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                    mOpenOverflow.run();
916517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                }
917517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            }
918517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        });
919517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
920517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mContentView.addView(mOpenOverflowButton);
921517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    break;
922517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
923517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
924517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return remainingMenuItems;
925517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
926517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
927517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) {
928517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOnMenuItemClickListener = listener;
9290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
9300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
931517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public View getView() {
932517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return mContentView;
9330c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
9340c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
935517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeIn(boolean animate) {
936517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            viewFader.fadeIn(animate);
937517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
938517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
939517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeOut(boolean animate) {
940517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            viewFader.fadeOut(animate);
9410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
9420c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
9430c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
944517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Returns how big this panel's view should be.
945517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * This method should only be called when the view has not been attached to a parent
946517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * otherwise it will throw an illegal state.
947517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
948517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public Size measure() throws IllegalStateException {
949517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Preconditions.checkState(mContentView.getParent() == null);
950517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
951517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());
952517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
953517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
954517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
955517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
956517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
957517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * A widget that holds the overflow items in the floating toolbar.
958517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
959517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static final class FloatingToolbarOverflowPanel {
960517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
961517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final LinearLayout mContentView;
962517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewGroup mBackButtonContainer;
963517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final View mBackButton;
964517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ListView mListView;
965f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private final TextView mListViewItemWidthCalculator;
966517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ViewFader mViewFader;
967517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final Runnable mCloseOverflow;
968517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
969517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
970f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private int mOverflowWidth = 0;
971517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
972517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
973517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Initializes a floating toolbar popup overflow view panel.
9740c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         *
975517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param context
976517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param closeOverflow  The code that closes the toolbar popup's overflow.
977517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
978517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) {
979517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mCloseOverflow = Preconditions.checkNotNull(closeOverflow);
980517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
981517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView = new LinearLayout(context);
982517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.setOrientation(LinearLayout.VERTICAL);
983517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mViewFader = new ViewFader(mContentView);
984517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
985517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mBackButton = LayoutInflater.from(context)
986517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    .inflate(R.layout.floating_popup_close_overflow_button, null);
987517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mBackButton.setOnClickListener(new View.OnClickListener() {
988517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
989517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                public void onClick(View v) {
990517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    mCloseOverflow.run();
991517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
992517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            });
993517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mBackButtonContainer = new LinearLayout(context);
994517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mBackButtonContainer.addView(mBackButton);
995517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
996f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mListView = createOverflowListView();
997517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
998517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                @Override
999517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
1000517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(position);
1001517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    if (mOnMenuItemClickListener != null) {
1002517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        mOnMenuItemClickListener.onMenuItemClick(menuItem);
1003517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    }
1004517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                }
1005517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            });
1006517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1007517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.addView(mListView);
1008517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.addView(mBackButtonContainer);
1009f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki
1010f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mListViewItemWidthCalculator = createOverflowMenuItemButton(context);
1011f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            mListViewItemWidthCalculator.setLayoutParams(new ViewGroup.LayoutParams(
1012f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
1013517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1014517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1015517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
1016517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Sets the menu items to be displayed in the overflow.
10170c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
1018517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void setMenuItems(List<MenuItem> menuItems) {
1019517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            ArrayAdapter overflowListViewAdapter = (ArrayAdapter) mListView.getAdapter();
1020517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListViewAdapter.clear();
1021517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListViewAdapter.addAll(menuItems);
1022517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            setListViewHeight();
1023f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            setOverflowWidth();
1024517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1025517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1026517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) {
1027517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mOnMenuItemClickListener = listener;
10280c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
10290c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
10300c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
1031517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Notifies the overflow of the current direction in which the overflow will be opened.
10320c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         *
1033517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @param overflowDirection  {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_UP}
1034517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         *   or {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_DOWN}.
10350c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
1036517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void setOverflowDirection(int overflowDirection) {
1037517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.removeView(mBackButtonContainer);
1038517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int index = (overflowDirection == FloatingToolbarPopup.OVERFLOW_DIRECTION_UP)? 1 : 0;
1039517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.addView(mBackButtonContainer, index);
10400c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
10410c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki
10420c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        /**
1043517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Returns the content view of the overflow.
1044517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         */
1045517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public View getView() {
1046517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return mContentView;
1047517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1048517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1049517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeIn(boolean animate) {
1050517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mViewFader.fadeIn(animate);
1051517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1052517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1053517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeOut(boolean animate) {
1054517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mViewFader.fadeOut(animate);
1055517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1056517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1057517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        /**
1058517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * Returns how big this panel's view should be.
1059517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * This method should only be called when the view has not been attached to a parent.
10600c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         *
1061517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki         * @throws IllegalStateException
10620c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki         */
1063517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public Size measure() {
1064517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            Preconditions.checkState(mContentView.getParent() == null);
1065517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
1066517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());
1067517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1068517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1069517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private void setListViewHeight() {
1070517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int itemHeight = getEstimatedToolbarHeight(mContentView.getContext());
1071517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int height = mListView.getAdapter().getCount() * itemHeight;
1072517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            int maxHeight = mContentView.getContext().getResources().
1073517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height);
1074517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            ViewGroup.LayoutParams params = mListView.getLayoutParams();
1075517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            params.height = Math.min(height, maxHeight);
1076517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mListView.setLayoutParams(params);
10770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki        }
1078517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1079f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private int setOverflowWidth() {
1080f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            for (int i = 0; i < mListView.getAdapter().getCount(); i++) {
1081f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(i);
1082f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                Preconditions.checkNotNull(menuItem);
1083f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                mListViewItemWidthCalculator.setText(menuItem.getTitle());
1084f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                mListViewItemWidthCalculator.measure(
1085f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                        MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
1086f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                mOverflowWidth = Math.max(
1087f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                        mListViewItemWidthCalculator.getMeasuredWidth(), mOverflowWidth);
1088f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            }
1089f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            return mOverflowWidth;
1090f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        }
1091f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki
1092f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki        private ListView createOverflowListView() {
1093f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki            final Context context = mContentView.getContext();
1094517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final ListView overflowListView = new ListView(context);
1095517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListView.setLayoutParams(new ViewGroup.LayoutParams(
1096517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
1097517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListView.setDivider(null);
1098517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListView.setDividerHeight(0);
1099517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            final ArrayAdapter overflowListViewAdapter =
1100517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    new ArrayAdapter<MenuItem>(context, 0) {
1101517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        @Override
1102517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        public View getView(int position, View convertView, ViewGroup parent) {
1103517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            TextView menuButton;
1104517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            if (convertView != null) {
1105517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                menuButton = (TextView) convertView;
1106517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            } else {
1107517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                                menuButton = createOverflowMenuItemButton(context);
1108517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            }
1109517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            MenuItem menuItem = getItem(position);
1110517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuButton.setText(menuItem.getTitle());
1111517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            menuButton.setContentDescription(menuItem.getTitle());
1112f8e14fd89b63c91ff441765827dda672c67fa1dbAbodunrinwa Toki                            menuButton.setMinimumWidth(mOverflowWidth);
1113517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                            return menuButton;
1114517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                        }
1115517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    };
1116517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            overflowListView.setAdapter(overflowListViewAdapter);
1117517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            return overflowListView;
1118517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1119517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1120517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1121517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1122517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1123517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * A helper for fading in or out a view.
1124517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1125517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static final class ViewFader {
1126517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1127517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private static final int FADE_OUT_DURATION = 250;
1128517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private static final int FADE_IN_DURATION = 150;
1129517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1130517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final View mView;
1131517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ObjectAnimator mFadeOutAnimation;
1132517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private final ObjectAnimator mFadeInAnimation;
1133517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1134517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        private ViewFader(View view) {
1135517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mView = Preconditions.checkNotNull(view);
1136517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mFadeOutAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0)
1137517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    .setDuration(FADE_OUT_DURATION);
1138517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            mFadeInAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1)
1139517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    .setDuration(FADE_IN_DURATION);
1140517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1141517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1142517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeIn(boolean animate) {
1143b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            cancelFadeAnimations();
1144517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (animate) {
1145517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mFadeInAnimation.start();
1146517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            } else {
1147517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mView.setAlpha(1);
1148517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
1149517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1150517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1151517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        public void fadeOut(boolean animate) {
1152b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            cancelFadeAnimations();
1153517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            if (animate) {
1154517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mFadeOutAnimation.start();
1155517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            } else {
1156517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                mView.setAlpha(0);
1157517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            }
1158517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1159b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki
1160b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        private void cancelFadeAnimations() {
1161b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mFadeInAnimation.cancel();
1162b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki            mFadeOutAnimation.cancel();
1163b90443724a5aa563cb81d6e7512329a66e80fa2cAbodunrinwa Toki        }
1164517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1165517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1166517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1167517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1168517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Creates and returns a menu button for the specified menu item.
1169517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1170517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static Button createMenuItemButton(Context context, MenuItem menuItem) {
1171517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        Button menuItemButton = (Button) LayoutInflater.from(context)
1172517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                .inflate(R.layout.floating_popup_menu_button, null);
1173517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        menuItemButton.setText(menuItem.getTitle());
1174517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        menuItemButton.setContentDescription(menuItem.getTitle());
1175517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return menuItemButton;
1176517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1177517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1178517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1179517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Creates and returns a styled floating toolbar overflow list view item.
1180517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1181517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static TextView createOverflowMenuItemButton(Context context) {
1182517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return (TextView) LayoutInflater.from(context)
1183517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                .inflate(R.layout.floating_popup_overflow_list_item, null);
1184517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1185517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1186517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static ViewGroup createContentContainer(Context context) {
1187517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return (ViewGroup) LayoutInflater.from(context)
1188517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                .inflate(R.layout.floating_popup_container, null);
1189517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1190517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1191517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static PopupWindow createPopupWindow(View content) {
1192517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        ViewGroup popupContentHolder = new LinearLayout(content.getContext());
1193517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        PopupWindow popupWindow = new PopupWindow(popupContentHolder);
1194103d48ec09cbaeedf28b66425cde9198f767e0d5Abodunrinwa Toki        popupWindow.setWindowLayoutType(
1195103d48ec09cbaeedf28b66425cde9198f767e0d5Abodunrinwa Toki                WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
1196517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        popupWindow.setAnimationStyle(0);
1197517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
1198517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        content.setLayoutParams(new ViewGroup.LayoutParams(
1199517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
1200517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        popupContentHolder.addView(content);
1201517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return popupWindow;
1202517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1203517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1204517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1205517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Creates a "grow and fade in from the bottom" animation for the specified view.
1206517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     *
1207517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * @param view  The view to animate
1208517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1209517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static AnimatorSet createGrowFadeInFromBottom(View view) {
1210517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        AnimatorSet growFadeInFromBottomAnimation =  new AnimatorSet();
1211517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        growFadeInFromBottomAnimation.playTogether(
1212517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125),
1213517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125),
1214517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75));
1215517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        growFadeInFromBottomAnimation.setStartDelay(50);
1216517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return growFadeInFromBottomAnimation;
1217517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1218517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1219517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1220517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Creates a "shrink and fade out from bottom" animation for the specified view.
1221517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     *
1222517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * @param view  The view to animate
1223517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * @param listener  The animation listener
1224517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1225517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static AnimatorSet createShrinkFadeOutFromBottomAnimation(
1226517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            View view, Animator.AnimatorListener listener) {
1227517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        AnimatorSet shrinkFadeOutFromBottomAnimation =  new AnimatorSet();
1228517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        shrinkFadeOutFromBottomAnimation.playTogether(
1229517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125),
1230517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75));
1231517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        shrinkFadeOutFromBottomAnimation.setStartDelay(150);
1232517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        shrinkFadeOutFromBottomAnimation.addListener(listener);
1233517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return shrinkFadeOutFromBottomAnimation;
1234517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1235517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1236517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getEstimatedToolbarHeight(Context context) {
1237517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return context.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_height);
1238517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1239517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1240517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getEstimatedOpenOverflowButtonWidth(Context context) {
1241517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return context.getResources()
1242517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                .getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_minimum_width);
1243517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1244517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1245517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getAdjustedToolbarWidth(Context context, int width) {
1246517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        if (width <= 0 || width > getScreenWidth(context)) {
1247517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki            width = context.getResources()
1248517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki                    .getDimensionPixelSize(R.dimen.floating_toolbar_default_width);
1249517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        }
1250517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return width;
1251517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1252517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1253517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1254517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Returns the device's screen width.
1255517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1256517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getScreenWidth(Context context) {
1257517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return context.getResources().getDisplayMetrics().widthPixels;
1258517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1259517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1260517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1261517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Returns the device's screen height.
1262517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1263517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int getScreenHeight(Context context) {
1264517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return context.getResources().getDisplayMetrics().heightPixels;
1265517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    }
1266517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki
1267517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    /**
1268517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * Returns value, restricted to the range min->max (inclusive).
1269517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * If maximum is less than minimum, the result is undefined.
1270517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     *
1271517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * @param value  The value to clamp.
1272517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * @param minimum  The minimum value in the range.
1273517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     * @param maximum  The maximum value in the range. Must not be less than minimum.
1274517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki     */
1275517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki    private static int clamp(int value, int minimum, int maximum) {
1276517adad1c44b40fddba84c067c987d6db3fc5840Abodunrinwa Toki        return Math.max(minimum, Math.min(value, maximum));
12770c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki    }
12780c7ed2886e6d17cacc9c0eeb2b7036923ef9a6e0Abodunrinwa Toki}
1279