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