Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.widget;
     18 
     19 import android.annotation.ColorInt;
     20 import android.annotation.DrawableRes;
     21 import android.annotation.MenuRes;
     22 import android.annotation.NonNull;
     23 import android.annotation.Nullable;
     24 import android.annotation.StringRes;
     25 import android.annotation.StyleRes;
     26 import android.annotation.TestApi;
     27 import android.annotation.UnsupportedAppUsage;
     28 import android.app.ActionBar;
     29 import android.content.Context;
     30 import android.content.res.TypedArray;
     31 import android.graphics.drawable.Drawable;
     32 import android.os.Build;
     33 import android.os.Parcel;
     34 import android.os.Parcelable;
     35 import android.text.Layout;
     36 import android.text.TextUtils;
     37 import android.util.AttributeSet;
     38 import android.view.CollapsibleActionView;
     39 import android.view.ContextThemeWrapper;
     40 import android.view.Gravity;
     41 import android.view.Menu;
     42 import android.view.MenuInflater;
     43 import android.view.MenuItem;
     44 import android.view.MotionEvent;
     45 import android.view.View;
     46 import android.view.ViewGroup;
     47 import android.view.ViewParent;
     48 import android.view.inspector.InspectableProperty;
     49 
     50 import com.android.internal.R;
     51 import com.android.internal.view.menu.MenuBuilder;
     52 import com.android.internal.view.menu.MenuItemImpl;
     53 import com.android.internal.view.menu.MenuPresenter;
     54 import com.android.internal.view.menu.MenuView;
     55 import com.android.internal.view.menu.SubMenuBuilder;
     56 import com.android.internal.widget.DecorToolbar;
     57 import com.android.internal.widget.ToolbarWidgetWrapper;
     58 
     59 import java.util.ArrayList;
     60 import java.util.List;
     61 
     62 /**
     63  * A standard toolbar for use within application content.
     64  *
     65  * <p>A Toolbar is a generalization of {@link android.app.ActionBar action bars} for use
     66  * within application layouts. While an action bar is traditionally part of an
     67  * {@link android.app.Activity Activity's} opaque window decor controlled by the framework,
     68  * a Toolbar may be placed at any arbitrary level of nesting within a view hierarchy.
     69  * An application may choose to designate a Toolbar as the action bar for an Activity
     70  * using the {@link android.app.Activity#setActionBar(Toolbar) setActionBar()} method.</p>
     71  *
     72  * <p>Toolbar supports a more focused feature set than ActionBar. From start to end, a toolbar
     73  * may contain a combination of the following optional elements:
     74  *
     75  * <ul>
     76  *     <li><em>A navigation button.</em> This may be an Up arrow, navigation menu toggle, close,
     77  *     collapse, done or another glyph of the app's choosing. This button should always be used
     78  *     to access other navigational destinations within the container of the Toolbar and
     79  *     its signified content or otherwise leave the current context signified by the Toolbar.
     80  *     The navigation button is vertically aligned within the Toolbar's
     81  *     {@link android.R.styleable#View_minHeight minimum height}, if set.</li>
     82  *     <li><em>A branded logo image.</em> This may extend to the height of the bar and can be
     83  *     arbitrarily wide.</li>
     84  *     <li><em>A title and subtitle.</em> The title should be a signpost for the Toolbar's current
     85  *     position in the navigation hierarchy and the content contained there. The subtitle,
     86  *     if present should indicate any extended information about the current content.
     87  *     If an app uses a logo image it should strongly consider omitting a title and subtitle.</li>
     88  *     <li><em>One or more custom views.</em> The application may add arbitrary child views
     89  *     to the Toolbar. They will appear at this position within the layout. If a child view's
     90  *     {@link LayoutParams} indicates a {@link Gravity} value of
     91  *     {@link Gravity#CENTER_HORIZONTAL CENTER_HORIZONTAL} the view will attempt to center
     92  *     within the available space remaining in the Toolbar after all other elements have been
     93  *     measured.</li>
     94  *     <li><em>An {@link ActionMenuView action menu}.</em> The menu of actions will pin to the
     95  *     end of the Toolbar offering a few
     96  *     <a href="http://developer.android.com/design/patterns/actionbar.html#ActionButtons">
     97  *     frequent, important or typical</a> actions along with an optional overflow menu for
     98  *     additional actions. Action buttons are vertically aligned within the Toolbar's
     99  *     {@link android.R.styleable#View_minHeight minimum height}, if set.</li>
    100  * </ul>
    101  * </p>
    102  *
    103  * <p>In modern Android UIs developers should lean more on a visually distinct color scheme for
    104  * toolbars than on their application icon. The use of application icon plus title as a standard
    105  * layout is discouraged on API 21 devices and newer.</p>
    106  *
    107  * @attr ref android.R.styleable#Toolbar_buttonGravity
    108  * @attr ref android.R.styleable#Toolbar_collapseContentDescription
    109  * @attr ref android.R.styleable#Toolbar_collapseIcon
    110  * @attr ref android.R.styleable#Toolbar_contentInsetEnd
    111  * @attr ref android.R.styleable#Toolbar_contentInsetLeft
    112  * @attr ref android.R.styleable#Toolbar_contentInsetRight
    113  * @attr ref android.R.styleable#Toolbar_contentInsetStart
    114  * @attr ref android.R.styleable#Toolbar_contentInsetStartWithNavigation
    115  * @attr ref android.R.styleable#Toolbar_contentInsetEndWithActions
    116  * @attr ref android.R.styleable#Toolbar_gravity
    117  * @attr ref android.R.styleable#Toolbar_logo
    118  * @attr ref android.R.styleable#Toolbar_logoDescription
    119  * @attr ref android.R.styleable#Toolbar_maxButtonHeight
    120  * @attr ref android.R.styleable#Toolbar_navigationContentDescription
    121  * @attr ref android.R.styleable#Toolbar_navigationIcon
    122  * @attr ref android.R.styleable#Toolbar_popupTheme
    123  * @attr ref android.R.styleable#Toolbar_subtitle
    124  * @attr ref android.R.styleable#Toolbar_subtitleTextAppearance
    125  * @attr ref android.R.styleable#Toolbar_subtitleTextColor
    126  * @attr ref android.R.styleable#Toolbar_title
    127  * @attr ref android.R.styleable#Toolbar_titleMargin
    128  * @attr ref android.R.styleable#Toolbar_titleMarginBottom
    129  * @attr ref android.R.styleable#Toolbar_titleMarginEnd
    130  * @attr ref android.R.styleable#Toolbar_titleMarginStart
    131  * @attr ref android.R.styleable#Toolbar_titleMarginTop
    132  * @attr ref android.R.styleable#Toolbar_titleTextAppearance
    133  * @attr ref android.R.styleable#Toolbar_titleTextColor
    134  */
    135 public class Toolbar extends ViewGroup {
    136     private static final String TAG = "Toolbar";
    137 
    138     private ActionMenuView mMenuView;
    139     @UnsupportedAppUsage
    140     private TextView mTitleTextView;
    141     private TextView mSubtitleTextView;
    142     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    143     private ImageButton mNavButtonView;
    144     private ImageView mLogoView;
    145 
    146     private Drawable mCollapseIcon;
    147     private CharSequence mCollapseDescription;
    148     private ImageButton mCollapseButtonView;
    149     View mExpandedActionView;
    150 
    151     /** Context against which to inflate popup menus. */
    152     private Context mPopupContext;
    153 
    154     /** Theme resource against which to inflate popup menus. */
    155     private int mPopupTheme;
    156 
    157     private int mTitleTextAppearance;
    158     private int mSubtitleTextAppearance;
    159     private int mNavButtonStyle;
    160 
    161     private int mButtonGravity;
    162 
    163     private int mMaxButtonHeight;
    164 
    165     @UnsupportedAppUsage
    166     private int mTitleMarginStart;
    167     @UnsupportedAppUsage
    168     private int mTitleMarginEnd;
    169     @UnsupportedAppUsage
    170     private int mTitleMarginTop;
    171     @UnsupportedAppUsage
    172     private int mTitleMarginBottom;
    173 
    174     private RtlSpacingHelper mContentInsets;
    175     private int mContentInsetStartWithNavigation;
    176     private int mContentInsetEndWithActions;
    177 
    178     private int mGravity = Gravity.START | Gravity.CENTER_VERTICAL;
    179 
    180     private CharSequence mTitleText;
    181     private CharSequence mSubtitleText;
    182 
    183     private int mTitleTextColor;
    184     private int mSubtitleTextColor;
    185 
    186     private boolean mEatingTouch;
    187 
    188     // Clear me after use.
    189     private final ArrayList<View> mTempViews = new ArrayList<View>();
    190 
    191     // Used to hold views that will be removed while we have an expanded action view.
    192     private final ArrayList<View> mHiddenViews = new ArrayList<>();
    193 
    194     private final int[] mTempMargins = new int[2];
    195 
    196     private OnMenuItemClickListener mOnMenuItemClickListener;
    197 
    198     private final ActionMenuView.OnMenuItemClickListener mMenuViewItemClickListener =
    199             new ActionMenuView.OnMenuItemClickListener() {
    200                 @Override
    201                 public boolean onMenuItemClick(MenuItem item) {
    202                     if (mOnMenuItemClickListener != null) {
    203                         return mOnMenuItemClickListener.onMenuItemClick(item);
    204                     }
    205                     return false;
    206                 }
    207             };
    208 
    209     private ToolbarWidgetWrapper mWrapper;
    210     private ActionMenuPresenter mOuterActionMenuPresenter;
    211     private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
    212     private MenuPresenter.Callback mActionMenuPresenterCallback;
    213     private MenuBuilder.Callback mMenuBuilderCallback;
    214 
    215     private boolean mCollapsible;
    216 
    217     private final Runnable mShowOverflowMenuRunnable = new Runnable() {
    218         @Override public void run() {
    219             showOverflowMenu();
    220         }
    221     };
    222 
    223     public Toolbar(Context context) {
    224         this(context, null);
    225     }
    226 
    227     public Toolbar(Context context, AttributeSet attrs) {
    228         this(context, attrs, com.android.internal.R.attr.toolbarStyle);
    229     }
    230 
    231     public Toolbar(Context context, AttributeSet attrs, int defStyleAttr) {
    232         this(context, attrs, defStyleAttr, 0);
    233     }
    234 
    235     public Toolbar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    236         super(context, attrs, defStyleAttr, defStyleRes);
    237 
    238         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar,
    239                 defStyleAttr, defStyleRes);
    240         saveAttributeDataForStyleable(context, R.styleable.Toolbar,
    241                 attrs, a, defStyleAttr, defStyleRes);
    242 
    243         mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
    244         mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
    245         mNavButtonStyle = a.getResourceId(R.styleable.Toolbar_navigationButtonStyle, 0);
    246         mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
    247         mButtonGravity = a.getInteger(R.styleable.Toolbar_buttonGravity, Gravity.TOP);
    248         mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom =
    249                 a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargin, 0);
    250 
    251         final int marginStart = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginStart, -1);
    252         if (marginStart >= 0) {
    253             mTitleMarginStart = marginStart;
    254         }
    255 
    256         final int marginEnd = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginEnd, -1);
    257         if (marginEnd >= 0) {
    258             mTitleMarginEnd = marginEnd;
    259         }
    260 
    261         final int marginTop = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginTop, -1);
    262         if (marginTop >= 0) {
    263             mTitleMarginTop = marginTop;
    264         }
    265 
    266         final int marginBottom = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginBottom,
    267                 -1);
    268         if (marginBottom >= 0) {
    269             mTitleMarginBottom = marginBottom;
    270         }
    271 
    272         mMaxButtonHeight = a.getDimensionPixelSize(R.styleable.Toolbar_maxButtonHeight, -1);
    273 
    274         final int contentInsetStart =
    275                 a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetStart,
    276                         RtlSpacingHelper.UNDEFINED);
    277         final int contentInsetEnd =
    278                 a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetEnd,
    279                         RtlSpacingHelper.UNDEFINED);
    280         final int contentInsetLeft =
    281                 a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetLeft, 0);
    282         final int contentInsetRight =
    283                 a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetRight, 0);
    284 
    285         ensureContentInsets();
    286         mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
    287 
    288         if (contentInsetStart != RtlSpacingHelper.UNDEFINED ||
    289                 contentInsetEnd != RtlSpacingHelper.UNDEFINED) {
    290             mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
    291         }
    292 
    293         mContentInsetStartWithNavigation = a.getDimensionPixelOffset(
    294                 R.styleable.Toolbar_contentInsetStartWithNavigation, RtlSpacingHelper.UNDEFINED);
    295         mContentInsetEndWithActions = a.getDimensionPixelOffset(
    296                 R.styleable.Toolbar_contentInsetEndWithActions, RtlSpacingHelper.UNDEFINED);
    297 
    298         mCollapseIcon = a.getDrawable(R.styleable.Toolbar_collapseIcon);
    299         mCollapseDescription = a.getText(R.styleable.Toolbar_collapseContentDescription);
    300 
    301         final CharSequence title = a.getText(R.styleable.Toolbar_title);
    302         if (!TextUtils.isEmpty(title)) {
    303             setTitle(title);
    304         }
    305 
    306         final CharSequence subtitle = a.getText(R.styleable.Toolbar_subtitle);
    307         if (!TextUtils.isEmpty(subtitle)) {
    308             setSubtitle(subtitle);
    309         }
    310 
    311         // Set the default context, since setPopupTheme() may be a no-op.
    312         mPopupContext = mContext;
    313         setPopupTheme(a.getResourceId(R.styleable.Toolbar_popupTheme, 0));
    314 
    315         final Drawable navIcon = a.getDrawable(R.styleable.Toolbar_navigationIcon);
    316         if (navIcon != null) {
    317             setNavigationIcon(navIcon);
    318         }
    319 
    320         final CharSequence navDesc = a.getText(
    321                 R.styleable.Toolbar_navigationContentDescription);
    322         if (!TextUtils.isEmpty(navDesc)) {
    323             setNavigationContentDescription(navDesc);
    324         }
    325 
    326         final Drawable logo = a.getDrawable(R.styleable.Toolbar_logo);
    327         if (logo != null) {
    328             setLogo(logo);
    329         }
    330 
    331         final CharSequence logoDesc = a.getText(R.styleable.Toolbar_logoDescription);
    332         if (!TextUtils.isEmpty(logoDesc)) {
    333             setLogoDescription(logoDesc);
    334         }
    335 
    336         if (a.hasValue(R.styleable.Toolbar_titleTextColor)) {
    337             setTitleTextColor(a.getColor(R.styleable.Toolbar_titleTextColor, 0xffffffff));
    338         }
    339 
    340         if (a.hasValue(R.styleable.Toolbar_subtitleTextColor)) {
    341             setSubtitleTextColor(a.getColor(R.styleable.Toolbar_subtitleTextColor, 0xffffffff));
    342         }
    343         a.recycle();
    344     }
    345 
    346     @Override
    347     protected void onAttachedToWindow() {
    348         super.onAttachedToWindow();
    349 
    350         // If the container is a cluster, unmark itself as a cluster to avoid having nested
    351         // clusters.
    352         ViewParent parent = getParent();
    353         while (parent != null && parent instanceof ViewGroup) {
    354             final ViewGroup vgParent = (ViewGroup) parent;
    355             if (vgParent.isKeyboardNavigationCluster()) {
    356                 setKeyboardNavigationCluster(false);
    357                 if (vgParent.getTouchscreenBlocksFocus()) {
    358                     setTouchscreenBlocksFocus(false);
    359                 }
    360                 break;
    361             }
    362             parent = vgParent.getParent();
    363         }
    364     }
    365 
    366     /**
    367      * Specifies the theme to use when inflating popup menus. By default, uses
    368      * the same theme as the toolbar itself.
    369      *
    370      * @param resId theme used to inflate popup menus
    371      * @see #getPopupTheme()
    372      */
    373     public void setPopupTheme(@StyleRes int resId) {
    374         if (mPopupTheme != resId) {
    375             mPopupTheme = resId;
    376             if (resId == 0) {
    377                 mPopupContext = mContext;
    378             } else {
    379                 mPopupContext = new ContextThemeWrapper(mContext, resId);
    380             }
    381         }
    382     }
    383 
    384     /**
    385      * @return resource identifier of the theme used to inflate popup menus, or
    386      *         0 if menus are inflated against the toolbar theme
    387      * @see #setPopupTheme(int)
    388      */
    389     @InspectableProperty
    390     public int getPopupTheme() {
    391         return mPopupTheme;
    392     }
    393 
    394     /**
    395      * Sets the title margin.
    396      *
    397      * @param start the starting title margin in pixels
    398      * @param top the top title margin in pixels
    399      * @param end the ending title margin in pixels
    400      * @param bottom the bottom title margin in pixels
    401      * @see #getTitleMarginStart()
    402      * @see #getTitleMarginTop()
    403      * @see #getTitleMarginEnd()
    404      * @see #getTitleMarginBottom()
    405      * @attr ref android.R.styleable#Toolbar_titleMargin
    406      */
    407     public void setTitleMargin(int start, int top, int end, int bottom) {
    408         mTitleMarginStart = start;
    409         mTitleMarginTop = top;
    410         mTitleMarginEnd = end;
    411         mTitleMarginBottom = bottom;
    412 
    413         requestLayout();
    414     }
    415 
    416     /**
    417      * @return the starting title margin in pixels
    418      * @see #setTitleMarginStart(int)
    419      * @attr ref android.R.styleable#Toolbar_titleMarginStart
    420      */
    421     @InspectableProperty
    422     public int getTitleMarginStart() {
    423         return mTitleMarginStart;
    424     }
    425 
    426     /**
    427      * Sets the starting title margin in pixels.
    428      *
    429      * @param margin the starting title margin in pixels
    430      * @see #getTitleMarginStart()
    431      * @attr ref android.R.styleable#Toolbar_titleMarginStart
    432      */
    433     public void setTitleMarginStart(int margin) {
    434         mTitleMarginStart = margin;
    435 
    436         requestLayout();
    437     }
    438 
    439     /**
    440      * @return the top title margin in pixels
    441      * @see #setTitleMarginTop(int)
    442      * @attr ref android.R.styleable#Toolbar_titleMarginTop
    443      */
    444     @InspectableProperty
    445     public int getTitleMarginTop() {
    446         return mTitleMarginTop;
    447     }
    448 
    449     /**
    450      * Sets the top title margin in pixels.
    451      *
    452      * @param margin the top title margin in pixels
    453      * @see #getTitleMarginTop()
    454      * @attr ref android.R.styleable#Toolbar_titleMarginTop
    455      */
    456     public void setTitleMarginTop(int margin) {
    457         mTitleMarginTop = margin;
    458 
    459         requestLayout();
    460     }
    461 
    462     /**
    463      * @return the ending title margin in pixels
    464      * @see #setTitleMarginEnd(int)
    465      * @attr ref android.R.styleable#Toolbar_titleMarginEnd
    466      */
    467     @InspectableProperty
    468     public int getTitleMarginEnd() {
    469         return mTitleMarginEnd;
    470     }
    471 
    472     /**
    473      * Sets the ending title margin in pixels.
    474      *
    475      * @param margin the ending title margin in pixels
    476      * @see #getTitleMarginEnd()
    477      * @attr ref android.R.styleable#Toolbar_titleMarginEnd
    478      */
    479     public void setTitleMarginEnd(int margin) {
    480         mTitleMarginEnd = margin;
    481 
    482         requestLayout();
    483     }
    484 
    485     /**
    486      * @return the bottom title margin in pixels
    487      * @see #setTitleMarginBottom(int)
    488      * @attr ref android.R.styleable#Toolbar_titleMarginBottom
    489      */
    490     @InspectableProperty
    491     public int getTitleMarginBottom() {
    492         return mTitleMarginBottom;
    493     }
    494 
    495     /**
    496      * Sets the bottom title margin in pixels.
    497      *
    498      * @param margin the bottom title margin in pixels
    499      * @see #getTitleMarginBottom()
    500      * @attr ref android.R.styleable#Toolbar_titleMarginBottom
    501      */
    502     public void setTitleMarginBottom(int margin) {
    503         mTitleMarginBottom = margin;
    504         requestLayout();
    505     }
    506 
    507     @Override
    508     public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
    509         super.onRtlPropertiesChanged(layoutDirection);
    510         ensureContentInsets();
    511         mContentInsets.setDirection(layoutDirection == LAYOUT_DIRECTION_RTL);
    512     }
    513 
    514     /**
    515      * Set a logo drawable from a resource id.
    516      *
    517      * <p>This drawable should generally take the place of title text. The logo cannot be
    518      * clicked. Apps using a logo should also supply a description using
    519      * {@link #setLogoDescription(int)}.</p>
    520      *
    521      * @param resId ID of a drawable resource
    522      */
    523     public void setLogo(@DrawableRes int resId) {
    524         setLogo(getContext().getDrawable(resId));
    525     }
    526 
    527     /** @hide */
    528     public boolean canShowOverflowMenu() {
    529         return getVisibility() == VISIBLE && mMenuView != null && mMenuView.isOverflowReserved();
    530     }
    531 
    532     /**
    533      * Check whether the overflow menu is currently showing. This may not reflect
    534      * a pending show operation in progress.
    535      *
    536      * @return true if the overflow menu is currently showing
    537      */
    538     public boolean isOverflowMenuShowing() {
    539         return mMenuView != null && mMenuView.isOverflowMenuShowing();
    540     }
    541 
    542     /** @hide */
    543     public boolean isOverflowMenuShowPending() {
    544         return mMenuView != null && mMenuView.isOverflowMenuShowPending();
    545     }
    546 
    547     /**
    548      * Show the overflow items from the associated menu.
    549      *
    550      * @return true if the menu was able to be shown, false otherwise
    551      */
    552     public boolean showOverflowMenu() {
    553         return mMenuView != null && mMenuView.showOverflowMenu();
    554     }
    555 
    556     /**
    557      * Hide the overflow items from the associated menu.
    558      *
    559      * @return true if the menu was able to be hidden, false otherwise
    560      */
    561     public boolean hideOverflowMenu() {
    562         return mMenuView != null && mMenuView.hideOverflowMenu();
    563     }
    564 
    565     /** @hide */
    566     public void setMenu(MenuBuilder menu, ActionMenuPresenter outerPresenter) {
    567         if (menu == null && mMenuView == null) {
    568             return;
    569         }
    570 
    571         ensureMenuView();
    572         final MenuBuilder oldMenu = mMenuView.peekMenu();
    573         if (oldMenu == menu) {
    574             return;
    575         }
    576 
    577         if (oldMenu != null) {
    578             oldMenu.removeMenuPresenter(mOuterActionMenuPresenter);
    579             oldMenu.removeMenuPresenter(mExpandedMenuPresenter);
    580         }
    581 
    582         if (mExpandedMenuPresenter == null) {
    583             mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
    584         }
    585 
    586         outerPresenter.setExpandedActionViewsExclusive(true);
    587         if (menu != null) {
    588             menu.addMenuPresenter(outerPresenter, mPopupContext);
    589             menu.addMenuPresenter(mExpandedMenuPresenter, mPopupContext);
    590         } else {
    591             outerPresenter.initForMenu(mPopupContext, null);
    592             mExpandedMenuPresenter.initForMenu(mPopupContext, null);
    593             outerPresenter.updateMenuView(true);
    594             mExpandedMenuPresenter.updateMenuView(true);
    595         }
    596         mMenuView.setPopupTheme(mPopupTheme);
    597         mMenuView.setPresenter(outerPresenter);
    598         mOuterActionMenuPresenter = outerPresenter;
    599     }
    600 
    601     /**
    602      * Dismiss all currently showing popup menus, including overflow or submenus.
    603      */
    604     public void dismissPopupMenus() {
    605         if (mMenuView != null) {
    606             mMenuView.dismissPopupMenus();
    607         }
    608     }
    609 
    610     /** @hide */
    611     public boolean isTitleTruncated() {
    612         if (mTitleTextView == null) {
    613             return false;
    614         }
    615 
    616         final Layout titleLayout = mTitleTextView.getLayout();
    617         if (titleLayout == null) {
    618             return false;
    619         }
    620 
    621         final int lineCount = titleLayout.getLineCount();
    622         for (int i = 0; i < lineCount; i++) {
    623             if (titleLayout.getEllipsisCount(i) > 0) {
    624                 return true;
    625             }
    626         }
    627         return false;
    628     }
    629 
    630     /**
    631      * Set a logo drawable.
    632      *
    633      * <p>This drawable should generally take the place of title text. The logo cannot be
    634      * clicked. Apps using a logo should also supply a description using
    635      * {@link #setLogoDescription(int)}.</p>
    636      *
    637      * @param drawable Drawable to use as a logo
    638      */
    639     public void setLogo(Drawable drawable) {
    640         if (drawable != null) {
    641             ensureLogoView();
    642             if (!isChildOrHidden(mLogoView)) {
    643                 addSystemView(mLogoView, true);
    644             }
    645         } else if (mLogoView != null && isChildOrHidden(mLogoView)) {
    646             removeView(mLogoView);
    647             mHiddenViews.remove(mLogoView);
    648         }
    649         if (mLogoView != null) {
    650             mLogoView.setImageDrawable(drawable);
    651         }
    652     }
    653 
    654     /**
    655      * Return the current logo drawable.
    656      *
    657      * @return The current logo drawable
    658      * @see #setLogo(int)
    659      * @see #setLogo(android.graphics.drawable.Drawable)
    660      */
    661     @InspectableProperty
    662     public Drawable getLogo() {
    663         return mLogoView != null ? mLogoView.getDrawable() : null;
    664     }
    665 
    666     /**
    667      * Set a description of the toolbar's logo.
    668      *
    669      * <p>This description will be used for accessibility or other similar descriptions
    670      * of the UI.</p>
    671      *
    672      * @param resId String resource id
    673      */
    674     public void setLogoDescription(@StringRes int resId) {
    675         setLogoDescription(getContext().getText(resId));
    676     }
    677 
    678     /**
    679      * Set a description of the toolbar's logo.
    680      *
    681      * <p>This description will be used for accessibility or other similar descriptions
    682      * of the UI.</p>
    683      *
    684      * @param description Description to set
    685      */
    686     public void setLogoDescription(CharSequence description) {
    687         if (!TextUtils.isEmpty(description)) {
    688             ensureLogoView();
    689         }
    690         if (mLogoView != null) {
    691             mLogoView.setContentDescription(description);
    692         }
    693     }
    694 
    695     /**
    696      * Return the description of the toolbar's logo.
    697      *
    698      * @return A description of the logo
    699      */
    700     @InspectableProperty
    701     public CharSequence getLogoDescription() {
    702         return mLogoView != null ? mLogoView.getContentDescription() : null;
    703     }
    704 
    705     private void ensureLogoView() {
    706         if (mLogoView == null) {
    707             mLogoView = new ImageView(getContext());
    708         }
    709     }
    710 
    711     /**
    712      * Check whether this Toolbar is currently hosting an expanded action view.
    713      *
    714      * <p>An action view may be expanded either directly from the
    715      * {@link android.view.MenuItem MenuItem} it belongs to or by user action. If the Toolbar
    716      * has an expanded action view it can be collapsed using the {@link #collapseActionView()}
    717      * method.</p>
    718      *
    719      * @return true if the Toolbar has an expanded action view
    720      */
    721     public boolean hasExpandedActionView() {
    722         return mExpandedMenuPresenter != null &&
    723                 mExpandedMenuPresenter.mCurrentExpandedItem != null;
    724     }
    725 
    726     /**
    727      * Collapse a currently expanded action view. If this Toolbar does not have an
    728      * expanded action view this method has no effect.
    729      *
    730      * <p>An action view may be expanded either directly from the
    731      * {@link android.view.MenuItem MenuItem} it belongs to or by user action.</p>
    732      *
    733      * @see #hasExpandedActionView()
    734      */
    735     public void collapseActionView() {
    736         final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
    737                 mExpandedMenuPresenter.mCurrentExpandedItem;
    738         if (item != null) {
    739             item.collapseActionView();
    740         }
    741     }
    742 
    743     /**
    744      * Returns the title of this toolbar.
    745      *
    746      * @return The current title.
    747      */
    748     @InspectableProperty
    749     public CharSequence getTitle() {
    750         return mTitleText;
    751     }
    752 
    753     /**
    754      * Set the title of this toolbar.
    755      *
    756      * <p>A title should be used as the anchor for a section of content. It should
    757      * describe or name the content being viewed.</p>
    758      *
    759      * @param resId Resource ID of a string to set as the title
    760      */
    761     public void setTitle(@StringRes int resId) {
    762         setTitle(getContext().getText(resId));
    763     }
    764 
    765     /**
    766      * Set the title of this toolbar.
    767      *
    768      * <p>A title should be used as the anchor for a section of content. It should
    769      * describe or name the content being viewed.</p>
    770      *
    771      * @param title Title to set
    772      */
    773     public void setTitle(CharSequence title) {
    774         if (!TextUtils.isEmpty(title)) {
    775             if (mTitleTextView == null) {
    776                 final Context context = getContext();
    777                 mTitleTextView = new TextView(context);
    778                 mTitleTextView.setSingleLine();
    779                 mTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
    780                 if (mTitleTextAppearance != 0) {
    781                     mTitleTextView.setTextAppearance(mTitleTextAppearance);
    782                 }
    783                 if (mTitleTextColor != 0) {
    784                     mTitleTextView.setTextColor(mTitleTextColor);
    785                 }
    786             }
    787             if (!isChildOrHidden(mTitleTextView)) {
    788                 addSystemView(mTitleTextView, true);
    789             }
    790         } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) {
    791             removeView(mTitleTextView);
    792             mHiddenViews.remove(mTitleTextView);
    793         }
    794         if (mTitleTextView != null) {
    795             mTitleTextView.setText(title);
    796         }
    797         mTitleText = title;
    798     }
    799 
    800     /**
    801      * Return the subtitle of this toolbar.
    802      *
    803      * @return The current subtitle
    804      */
    805     @InspectableProperty
    806     public CharSequence getSubtitle() {
    807         return mSubtitleText;
    808     }
    809 
    810     /**
    811      * Set the subtitle of this toolbar.
    812      *
    813      * <p>Subtitles should express extended information about the current content.</p>
    814      *
    815      * @param resId String resource ID
    816      */
    817     public void setSubtitle(@StringRes int resId) {
    818         setSubtitle(getContext().getText(resId));
    819     }
    820 
    821     /**
    822      * Set the subtitle of this toolbar.
    823      *
    824      * <p>Subtitles should express extended information about the current content.</p>
    825      *
    826      * @param subtitle Subtitle to set
    827      */
    828     public void setSubtitle(CharSequence subtitle) {
    829         if (!TextUtils.isEmpty(subtitle)) {
    830             if (mSubtitleTextView == null) {
    831                 final Context context = getContext();
    832                 mSubtitleTextView = new TextView(context);
    833                 mSubtitleTextView.setSingleLine();
    834                 mSubtitleTextView.setEllipsize(TextUtils.TruncateAt.END);
    835                 if (mSubtitleTextAppearance != 0) {
    836                     mSubtitleTextView.setTextAppearance(mSubtitleTextAppearance);
    837                 }
    838                 if (mSubtitleTextColor != 0) {
    839                     mSubtitleTextView.setTextColor(mSubtitleTextColor);
    840                 }
    841             }
    842             if (!isChildOrHidden(mSubtitleTextView)) {
    843                 addSystemView(mSubtitleTextView, true);
    844             }
    845         } else if (mSubtitleTextView != null && isChildOrHidden(mSubtitleTextView)) {
    846             removeView(mSubtitleTextView);
    847             mHiddenViews.remove(mSubtitleTextView);
    848         }
    849         if (mSubtitleTextView != null) {
    850             mSubtitleTextView.setText(subtitle);
    851         }
    852         mSubtitleText = subtitle;
    853     }
    854 
    855     /**
    856      * Sets the text color, size, style, hint color, and highlight color
    857      * from the specified TextAppearance resource.
    858      */
    859     public void setTitleTextAppearance(Context context, @StyleRes int resId) {
    860         mTitleTextAppearance = resId;
    861         if (mTitleTextView != null) {
    862             mTitleTextView.setTextAppearance(resId);
    863         }
    864     }
    865 
    866     /**
    867      * Sets the text color, size, style, hint color, and highlight color
    868      * from the specified TextAppearance resource.
    869      */
    870     public void setSubtitleTextAppearance(Context context, @StyleRes int resId) {
    871         mSubtitleTextAppearance = resId;
    872         if (mSubtitleTextView != null) {
    873             mSubtitleTextView.setTextAppearance(resId);
    874         }
    875     }
    876 
    877     /**
    878      * Sets the text color of the title, if present.
    879      *
    880      * @param color The new text color in 0xAARRGGBB format
    881      */
    882     public void setTitleTextColor(@ColorInt int color) {
    883         mTitleTextColor = color;
    884         if (mTitleTextView != null) {
    885             mTitleTextView.setTextColor(color);
    886         }
    887     }
    888 
    889     /**
    890      * Sets the text color of the subtitle, if present.
    891      *
    892      * @param color The new text color in 0xAARRGGBB format
    893      */
    894     public void setSubtitleTextColor(@ColorInt int color) {
    895         mSubtitleTextColor = color;
    896         if (mSubtitleTextView != null) {
    897             mSubtitleTextView.setTextColor(color);
    898         }
    899     }
    900 
    901     /**
    902      * Retrieve the currently configured content description for the navigation button view.
    903      * This will be used to describe the navigation action to users through mechanisms such
    904      * as screen readers or tooltips.
    905      *
    906      * @return The navigation button's content description
    907      *
    908      * @attr ref android.R.styleable#Toolbar_navigationContentDescription
    909      */
    910     @InspectableProperty
    911     @Nullable
    912     public CharSequence getNavigationContentDescription() {
    913         return mNavButtonView != null ? mNavButtonView.getContentDescription() : null;
    914     }
    915 
    916     /**
    917      * Set a content description for the navigation button if one is present. The content
    918      * description will be read via screen readers or other accessibility systems to explain
    919      * the action of the navigation button.
    920      *
    921      * @param resId Resource ID of a content description string to set, or 0 to
    922      *              clear the description
    923      *
    924      * @attr ref android.R.styleable#Toolbar_navigationContentDescription
    925      */
    926     public void setNavigationContentDescription(@StringRes int resId) {
    927         setNavigationContentDescription(resId != 0 ? getContext().getText(resId) : null);
    928     }
    929 
    930     /**
    931      * Set a content description for the navigation button if one is present. The content
    932      * description will be read via screen readers or other accessibility systems to explain
    933      * the action of the navigation button.
    934      *
    935      * @param description Content description to set, or <code>null</code> to
    936      *                    clear the content description
    937      *
    938      * @attr ref android.R.styleable#Toolbar_navigationContentDescription
    939      */
    940     public void setNavigationContentDescription(@Nullable CharSequence description) {
    941         if (!TextUtils.isEmpty(description)) {
    942             ensureNavButtonView();
    943         }
    944         if (mNavButtonView != null) {
    945             mNavButtonView.setContentDescription(description);
    946         }
    947     }
    948 
    949     /**
    950      * Set the icon to use for the toolbar's navigation button.
    951      *
    952      * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
    953      * will make the navigation button visible.</p>
    954      *
    955      * <p>If you use a navigation icon you should also set a description for its action using
    956      * {@link #setNavigationContentDescription(int)}. This is used for accessibility and
    957      * tooltips.</p>
    958      *
    959      * @param resId Resource ID of a drawable to set
    960      *
    961      * @attr ref android.R.styleable#Toolbar_navigationIcon
    962      */
    963     public void setNavigationIcon(@DrawableRes int resId) {
    964         setNavigationIcon(getContext().getDrawable(resId));
    965     }
    966 
    967     /**
    968      * Set the icon to use for the toolbar's navigation button.
    969      *
    970      * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
    971      * will make the navigation button visible.</p>
    972      *
    973      * <p>If you use a navigation icon you should also set a description for its action using
    974      * {@link #setNavigationContentDescription(int)}. This is used for accessibility and
    975      * tooltips.</p>
    976      *
    977      * @param icon Drawable to set, may be null to clear the icon
    978      *
    979      * @attr ref android.R.styleable#Toolbar_navigationIcon
    980      */
    981     public void setNavigationIcon(@Nullable Drawable icon) {
    982         if (icon != null) {
    983             ensureNavButtonView();
    984             if (!isChildOrHidden(mNavButtonView)) {
    985                 addSystemView(mNavButtonView, true);
    986             }
    987         } else if (mNavButtonView != null && isChildOrHidden(mNavButtonView)) {
    988             removeView(mNavButtonView);
    989             mHiddenViews.remove(mNavButtonView);
    990         }
    991         if (mNavButtonView != null) {
    992             mNavButtonView.setImageDrawable(icon);
    993         }
    994     }
    995 
    996     /**
    997      * Return the current drawable used as the navigation icon.
    998      *
    999      * @return The navigation icon drawable
   1000      *
   1001      * @attr ref android.R.styleable#Toolbar_navigationIcon
   1002      */
   1003     @InspectableProperty
   1004     @Nullable
   1005     public Drawable getNavigationIcon() {
   1006         return mNavButtonView != null ? mNavButtonView.getDrawable() : null;
   1007     }
   1008 
   1009     /**
   1010      * Set a listener to respond to navigation events.
   1011      *
   1012      * <p>This listener will be called whenever the user clicks the navigation button
   1013      * at the start of the toolbar. An icon must be set for the navigation button to appear.</p>
   1014      *
   1015      * @param listener Listener to set
   1016      * @see #setNavigationIcon(android.graphics.drawable.Drawable)
   1017      */
   1018     public void setNavigationOnClickListener(OnClickListener listener) {
   1019         ensureNavButtonView();
   1020         mNavButtonView.setOnClickListener(listener);
   1021     }
   1022 
   1023     /**
   1024      * @hide
   1025      */
   1026     @Nullable
   1027     @TestApi
   1028     public View getNavigationView() {
   1029         return mNavButtonView;
   1030     }
   1031 
   1032     /**
   1033      * Retrieve the currently configured content description for the collapse button view.
   1034      * This will be used to describe the collapse action to users through mechanisms such
   1035      * as screen readers or tooltips.
   1036      *
   1037      * @return The collapse button's content description
   1038      *
   1039      * @attr ref android.R.styleable#Toolbar_collapseContentDescription
   1040      */
   1041     @InspectableProperty
   1042     @Nullable
   1043     public CharSequence getCollapseContentDescription() {
   1044         return mCollapseButtonView != null ? mCollapseButtonView.getContentDescription() : null;
   1045     }
   1046 
   1047     /**
   1048      * Set a content description for the collapse button if one is present. The content description
   1049      * will be read via screen readers or other accessibility systems to explain the action of the
   1050      * collapse button.
   1051      *
   1052      * @param resId Resource ID of a content description string to set, or 0 to
   1053      *              clear the description
   1054      *
   1055      * @attr ref android.R.styleable#Toolbar_collapseContentDescription
   1056      */
   1057     public void setCollapseContentDescription(@StringRes int resId) {
   1058         setCollapseContentDescription(resId != 0 ? getContext().getText(resId) : null);
   1059     }
   1060 
   1061     /**
   1062      * Set a content description for the collapse button if one is present. The content description
   1063      * will be read via screen readers or other accessibility systems to explain the action of the
   1064      * navigation button.
   1065      *
   1066      * @param description Content description to set, or <code>null</code> to
   1067      *                    clear the content description
   1068      *
   1069      * @attr ref android.R.styleable#Toolbar_collapseContentDescription
   1070      */
   1071     public void setCollapseContentDescription(@Nullable CharSequence description) {
   1072         if (!TextUtils.isEmpty(description)) {
   1073             ensureCollapseButtonView();
   1074         }
   1075         if (mCollapseButtonView != null) {
   1076             mCollapseButtonView.setContentDescription(description);
   1077         }
   1078     }
   1079 
   1080     /**
   1081      * Return the current drawable used as the collapse icon.
   1082      *
   1083      * @return The collapse icon drawable
   1084      *
   1085      * @attr ref android.R.styleable#Toolbar_collapseIcon
   1086      */
   1087     @InspectableProperty
   1088     @Nullable
   1089     public Drawable getCollapseIcon() {
   1090         return mCollapseButtonView != null ? mCollapseButtonView.getDrawable() : null;
   1091     }
   1092 
   1093     /**
   1094      * Set the icon to use for the toolbar's collapse button.
   1095      *
   1096      * <p>The collapse button appears at the start of the toolbar when an action view is present
   1097      * .</p>
   1098      *
   1099      * @param resId Resource ID of a drawable to set
   1100      *
   1101      * @attr ref android.R.styleable#Toolbar_collapseIcon
   1102      */
   1103     public void setCollapseIcon(@DrawableRes int resId) {
   1104         setCollapseIcon(getContext().getDrawable(resId));
   1105     }
   1106 
   1107     /**
   1108      * Set the icon to use for the toolbar's collapse button.
   1109      *
   1110      * <p>The collapse button appears at the start of the toolbar when an action view is present
   1111      * .</p>
   1112      *
   1113      * @param icon Drawable to set, may be null to use the default icon
   1114      *
   1115      * @attr ref android.R.styleable#Toolbar_collapseIcon
   1116      */
   1117     public void setCollapseIcon(@Nullable Drawable icon) {
   1118         if (icon != null) {
   1119             ensureCollapseButtonView();
   1120             mCollapseButtonView.setImageDrawable(icon);
   1121         } else if (mCollapseButtonView != null) {
   1122             mCollapseButtonView.setImageDrawable(mCollapseIcon);
   1123         }
   1124     }
   1125 
   1126     /**
   1127      * Return the Menu shown in the toolbar.
   1128      *
   1129      * <p>Applications that wish to populate the toolbar's menu can do so from here. To use
   1130      * an XML menu resource, use {@link #inflateMenu(int)}.</p>
   1131      *
   1132      * @return The toolbar's Menu
   1133      */
   1134     public Menu getMenu() {
   1135         ensureMenu();
   1136         return mMenuView.getMenu();
   1137     }
   1138 
   1139     /**
   1140      * Set the icon to use for the overflow button.
   1141      *
   1142      * @param icon Drawable to set, may be null to clear the icon
   1143      */
   1144     public void setOverflowIcon(@Nullable Drawable icon) {
   1145         ensureMenu();
   1146         mMenuView.setOverflowIcon(icon);
   1147     }
   1148 
   1149     /**
   1150      * Return the current drawable used as the overflow icon.
   1151      *
   1152      * @return The overflow icon drawable
   1153      */
   1154     @Nullable
   1155     public Drawable getOverflowIcon() {
   1156         ensureMenu();
   1157         return mMenuView.getOverflowIcon();
   1158     }
   1159 
   1160     private void ensureMenu() {
   1161         ensureMenuView();
   1162         if (mMenuView.peekMenu() == null) {
   1163             // Initialize a new menu for the first time.
   1164             final MenuBuilder menu = (MenuBuilder) mMenuView.getMenu();
   1165             if (mExpandedMenuPresenter == null) {
   1166                 mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
   1167             }
   1168             mMenuView.setExpandedActionViewsExclusive(true);
   1169             menu.addMenuPresenter(mExpandedMenuPresenter, mPopupContext);
   1170         }
   1171     }
   1172 
   1173     private void ensureMenuView() {
   1174         if (mMenuView == null) {
   1175             mMenuView = new ActionMenuView(getContext());
   1176             mMenuView.setPopupTheme(mPopupTheme);
   1177             mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener);
   1178             mMenuView.setMenuCallbacks(mActionMenuPresenterCallback, mMenuBuilderCallback);
   1179             final LayoutParams lp = generateDefaultLayoutParams();
   1180             lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
   1181             mMenuView.setLayoutParams(lp);
   1182             addSystemView(mMenuView, false);
   1183         }
   1184     }
   1185 
   1186     private MenuInflater getMenuInflater() {
   1187         return new MenuInflater(getContext());
   1188     }
   1189 
   1190     /**
   1191      * Inflate a menu resource into this toolbar.
   1192      *
   1193      * <p>Inflate an XML menu resource into this toolbar. Existing items in the menu will not
   1194      * be modified or removed.</p>
   1195      *
   1196      * @param resId ID of a menu resource to inflate
   1197      */
   1198     public void inflateMenu(@MenuRes int resId) {
   1199         getMenuInflater().inflate(resId, getMenu());
   1200     }
   1201 
   1202     /**
   1203      * Set a listener to respond to menu item click events.
   1204      *
   1205      * <p>This listener will be invoked whenever a user selects a menu item from
   1206      * the action buttons presented at the end of the toolbar or the associated overflow.</p>
   1207      *
   1208      * @param listener Listener to set
   1209      */
   1210     public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
   1211         mOnMenuItemClickListener = listener;
   1212     }
   1213 
   1214     /**
   1215      * Sets the content insets for this toolbar relative to layout direction.
   1216      *
   1217      * <p>The content inset affects the valid area for Toolbar content other than
   1218      * the navigation button and menu. Insets define the minimum margin for these components
   1219      * and can be used to effectively align Toolbar content along well-known gridlines.</p>
   1220      *
   1221      * @param contentInsetStart Content inset for the toolbar starting edge
   1222      * @param contentInsetEnd Content inset for the toolbar ending edge
   1223      *
   1224      * @see #setContentInsetsAbsolute(int, int)
   1225      * @see #getContentInsetStart()
   1226      * @see #getContentInsetEnd()
   1227      * @see #getContentInsetLeft()
   1228      * @see #getContentInsetRight()
   1229      * @attr ref android.R.styleable#Toolbar_contentInsetEnd
   1230      * @attr ref android.R.styleable#Toolbar_contentInsetStart
   1231      */
   1232     public void setContentInsetsRelative(int contentInsetStart, int contentInsetEnd) {
   1233         ensureContentInsets();
   1234         mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
   1235     }
   1236 
   1237     /**
   1238      * Gets the starting content inset for this toolbar.
   1239      *
   1240      * <p>The content inset affects the valid area for Toolbar content other than
   1241      * the navigation button and menu. Insets define the minimum margin for these components
   1242      * and can be used to effectively align Toolbar content along well-known gridlines.</p>
   1243      *
   1244      * @return The starting content inset for this toolbar
   1245      *
   1246      * @see #setContentInsetsRelative(int, int)
   1247      * @see #setContentInsetsAbsolute(int, int)
   1248      * @see #getContentInsetEnd()
   1249      * @see #getContentInsetLeft()
   1250      * @see #getContentInsetRight()
   1251      * @attr ref android.R.styleable#Toolbar_contentInsetStart
   1252      */
   1253     @InspectableProperty
   1254     public int getContentInsetStart() {
   1255         return mContentInsets != null ? mContentInsets.getStart() : 0;
   1256     }
   1257 
   1258     /**
   1259      * Gets the ending content inset for this toolbar.
   1260      *
   1261      * <p>The content inset affects the valid area for Toolbar content other than
   1262      * the navigation button and menu. Insets define the minimum margin for these components
   1263      * and can be used to effectively align Toolbar content along well-known gridlines.</p>
   1264      *
   1265      * @return The ending content inset for this toolbar
   1266      *
   1267      * @see #setContentInsetsRelative(int, int)
   1268      * @see #setContentInsetsAbsolute(int, int)
   1269      * @see #getContentInsetStart()
   1270      * @see #getContentInsetLeft()
   1271      * @see #getContentInsetRight()
   1272      * @attr ref android.R.styleable#Toolbar_contentInsetEnd
   1273      */
   1274     @InspectableProperty
   1275     public int getContentInsetEnd() {
   1276         return mContentInsets != null ? mContentInsets.getEnd() : 0;
   1277     }
   1278 
   1279     /**
   1280      * Sets the content insets for this toolbar.
   1281      *
   1282      * <p>The content inset affects the valid area for Toolbar content other than
   1283      * the navigation button and menu. Insets define the minimum margin for these components
   1284      * and can be used to effectively align Toolbar content along well-known gridlines.</p>
   1285      *
   1286      * @param contentInsetLeft Content inset for the toolbar's left edge
   1287      * @param contentInsetRight Content inset for the toolbar's right edge
   1288      *
   1289      * @see #setContentInsetsAbsolute(int, int)
   1290      * @see #getContentInsetStart()
   1291      * @see #getContentInsetEnd()
   1292      * @see #getContentInsetLeft()
   1293      * @see #getContentInsetRight()
   1294      * @attr ref android.R.styleable#Toolbar_contentInsetLeft
   1295      * @attr ref android.R.styleable#Toolbar_contentInsetRight
   1296      */
   1297     public void setContentInsetsAbsolute(int contentInsetLeft, int contentInsetRight) {
   1298         ensureContentInsets();
   1299         mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
   1300     }
   1301 
   1302     /**
   1303      * Gets the left content inset for this toolbar.
   1304      *
   1305      * <p>The content inset affects the valid area for Toolbar content other than
   1306      * the navigation button and menu. Insets define the minimum margin for these components
   1307      * and can be used to effectively align Toolbar content along well-known gridlines.</p>
   1308      *
   1309      * @return The left content inset for this toolbar
   1310      *
   1311      * @see #setContentInsetsRelative(int, int)
   1312      * @see #setContentInsetsAbsolute(int, int)
   1313      * @see #getContentInsetStart()
   1314      * @see #getContentInsetEnd()
   1315      * @see #getContentInsetRight()
   1316      * @attr ref android.R.styleable#Toolbar_contentInsetLeft
   1317      */
   1318     @InspectableProperty
   1319     public int getContentInsetLeft() {
   1320         return mContentInsets != null ? mContentInsets.getLeft() : 0;
   1321     }
   1322 
   1323     /**
   1324      * Gets the right content inset for this toolbar.
   1325      *
   1326      * <p>The content inset affects the valid area for Toolbar content other than
   1327      * the navigation button and menu. Insets define the minimum margin for these components
   1328      * and can be used to effectively align Toolbar content along well-known gridlines.</p>
   1329      *
   1330      * @return The right content inset for this toolbar
   1331      *
   1332      * @see #setContentInsetsRelative(int, int)
   1333      * @see #setContentInsetsAbsolute(int, int)
   1334      * @see #getContentInsetStart()
   1335      * @see #getContentInsetEnd()
   1336      * @see #getContentInsetLeft()
   1337      * @attr ref android.R.styleable#Toolbar_contentInsetRight
   1338      */
   1339     @InspectableProperty
   1340     public int getContentInsetRight() {
   1341         return mContentInsets != null ? mContentInsets.getRight() : 0;
   1342     }
   1343 
   1344     /**
   1345      * Gets the start content inset to use when a navigation button is present.
   1346      *
   1347      * <p>Different content insets are often called for when additional buttons are present
   1348      * in the toolbar, as well as at different toolbar sizes. The larger value of
   1349      * {@link #getContentInsetStart()} and this value will be used during layout.</p>
   1350      *
   1351      * @return the start content inset used when a navigation icon has been set in pixels
   1352      *
   1353      * @see #setContentInsetStartWithNavigation(int)
   1354      * @attr ref android.R.styleable#Toolbar_contentInsetStartWithNavigation
   1355      */
   1356     @InspectableProperty
   1357     public int getContentInsetStartWithNavigation() {
   1358         return mContentInsetStartWithNavigation != RtlSpacingHelper.UNDEFINED
   1359                 ? mContentInsetStartWithNavigation
   1360                 : getContentInsetStart();
   1361     }
   1362 
   1363     /**
   1364      * Sets the start content inset to use when a navigation button is present.
   1365      *
   1366      * <p>Different content insets are often called for when additional buttons are present
   1367      * in the toolbar, as well as at different toolbar sizes. The larger value of
   1368      * {@link #getContentInsetStart()} and this value will be used during layout.</p>
   1369      *
   1370      * @param insetStartWithNavigation the inset to use when a navigation icon has been set
   1371      *                                 in pixels
   1372      *
   1373      * @see #getContentInsetStartWithNavigation()
   1374      * @attr ref android.R.styleable#Toolbar_contentInsetStartWithNavigation
   1375      */
   1376     public void setContentInsetStartWithNavigation(int insetStartWithNavigation) {
   1377         if (insetStartWithNavigation < 0) {
   1378             insetStartWithNavigation = RtlSpacingHelper.UNDEFINED;
   1379         }
   1380         if (insetStartWithNavigation != mContentInsetStartWithNavigation) {
   1381             mContentInsetStartWithNavigation = insetStartWithNavigation;
   1382             if (getNavigationIcon() != null) {
   1383                 requestLayout();
   1384             }
   1385         }
   1386     }
   1387 
   1388     /**
   1389      * Gets the end content inset to use when action buttons are present.
   1390      *
   1391      * <p>Different content insets are often called for when additional buttons are present
   1392      * in the toolbar, as well as at different toolbar sizes. The larger value of
   1393      * {@link #getContentInsetEnd()} and this value will be used during layout.</p>
   1394      *
   1395      * @return the end content inset used when a menu has been set in pixels
   1396      *
   1397      * @see #setContentInsetEndWithActions(int)
   1398      * @attr ref android.R.styleable#Toolbar_contentInsetEndWithActions
   1399      */
   1400     @InspectableProperty
   1401     public int getContentInsetEndWithActions() {
   1402         return mContentInsetEndWithActions != RtlSpacingHelper.UNDEFINED
   1403                 ? mContentInsetEndWithActions
   1404                 : getContentInsetEnd();
   1405     }
   1406 
   1407     /**
   1408      * Sets the start content inset to use when action buttons are present.
   1409      *
   1410      * <p>Different content insets are often called for when additional buttons are present
   1411      * in the toolbar, as well as at different toolbar sizes. The larger value of
   1412      * {@link #getContentInsetEnd()} and this value will be used during layout.</p>
   1413      *
   1414      * @param insetEndWithActions the inset to use when a menu has been set in pixels
   1415      *
   1416      * @see #setContentInsetEndWithActions(int)
   1417      * @attr ref android.R.styleable#Toolbar_contentInsetEndWithActions
   1418      */
   1419     public void setContentInsetEndWithActions(int insetEndWithActions) {
   1420         if (insetEndWithActions < 0) {
   1421             insetEndWithActions = RtlSpacingHelper.UNDEFINED;
   1422         }
   1423         if (insetEndWithActions != mContentInsetEndWithActions) {
   1424             mContentInsetEndWithActions = insetEndWithActions;
   1425             if (getNavigationIcon() != null) {
   1426                 requestLayout();
   1427             }
   1428         }
   1429     }
   1430 
   1431     /**
   1432      * Gets the content inset that will be used on the starting side of the bar in the current
   1433      * toolbar configuration.
   1434      *
   1435      * @return the current content inset start in pixels
   1436      *
   1437      * @see #getContentInsetStartWithNavigation()
   1438      */
   1439     public int getCurrentContentInsetStart() {
   1440         return getNavigationIcon() != null
   1441                 ? Math.max(getContentInsetStart(), Math.max(mContentInsetStartWithNavigation, 0))
   1442                 : getContentInsetStart();
   1443     }
   1444 
   1445     /**
   1446      * Gets the content inset that will be used on the ending side of the bar in the current
   1447      * toolbar configuration.
   1448      *
   1449      * @return the current content inset end in pixels
   1450      *
   1451      * @see #getContentInsetEndWithActions()
   1452      */
   1453     public int getCurrentContentInsetEnd() {
   1454         boolean hasActions = false;
   1455         if (mMenuView != null) {
   1456             final MenuBuilder mb = mMenuView.peekMenu();
   1457             hasActions = mb != null && mb.hasVisibleItems();
   1458         }
   1459         return hasActions
   1460                 ? Math.max(getContentInsetEnd(), Math.max(mContentInsetEndWithActions, 0))
   1461                 : getContentInsetEnd();
   1462     }
   1463 
   1464     /**
   1465      * Gets the content inset that will be used on the left side of the bar in the current
   1466      * toolbar configuration.
   1467      *
   1468      * @return the current content inset left in pixels
   1469      *
   1470      * @see #getContentInsetStartWithNavigation()
   1471      * @see #getContentInsetEndWithActions()
   1472      */
   1473     public int getCurrentContentInsetLeft() {
   1474         return isLayoutRtl()
   1475                 ? getCurrentContentInsetEnd()
   1476                 : getCurrentContentInsetStart();
   1477     }
   1478 
   1479     /**
   1480      * Gets the content inset that will be used on the right side of the bar in the current
   1481      * toolbar configuration.
   1482      *
   1483      * @return the current content inset right in pixels
   1484      *
   1485      * @see #getContentInsetStartWithNavigation()
   1486      * @see #getContentInsetEndWithActions()
   1487      */
   1488     public int getCurrentContentInsetRight() {
   1489         return isLayoutRtl()
   1490                 ? getCurrentContentInsetStart()
   1491                 : getCurrentContentInsetEnd();
   1492     }
   1493 
   1494     private void ensureNavButtonView() {
   1495         if (mNavButtonView == null) {
   1496             mNavButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
   1497             final LayoutParams lp = generateDefaultLayoutParams();
   1498             lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
   1499             mNavButtonView.setLayoutParams(lp);
   1500         }
   1501     }
   1502 
   1503     private void ensureCollapseButtonView() {
   1504         if (mCollapseButtonView == null) {
   1505             mCollapseButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
   1506             mCollapseButtonView.setImageDrawable(mCollapseIcon);
   1507             mCollapseButtonView.setContentDescription(mCollapseDescription);
   1508             final LayoutParams lp = generateDefaultLayoutParams();
   1509             lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
   1510             lp.mViewType = LayoutParams.EXPANDED;
   1511             mCollapseButtonView.setLayoutParams(lp);
   1512             mCollapseButtonView.setOnClickListener(new OnClickListener() {
   1513                 @Override
   1514                 public void onClick(View v) {
   1515                     collapseActionView();
   1516                 }
   1517             });
   1518         }
   1519     }
   1520 
   1521     private void addSystemView(View v, boolean allowHide) {
   1522         final ViewGroup.LayoutParams vlp = v.getLayoutParams();
   1523         final LayoutParams lp;
   1524         if (vlp == null) {
   1525             lp = generateDefaultLayoutParams();
   1526         } else if (!checkLayoutParams(vlp)) {
   1527             lp = generateLayoutParams(vlp);
   1528         } else {
   1529             lp = (LayoutParams) vlp;
   1530         }
   1531         lp.mViewType = LayoutParams.SYSTEM;
   1532 
   1533         if (allowHide && mExpandedActionView != null) {
   1534             v.setLayoutParams(lp);
   1535             mHiddenViews.add(v);
   1536         } else {
   1537             addView(v, lp);
   1538         }
   1539     }
   1540 
   1541     @Override
   1542     protected Parcelable onSaveInstanceState() {
   1543         SavedState state = new SavedState(super.onSaveInstanceState());
   1544 
   1545         if (mExpandedMenuPresenter != null && mExpandedMenuPresenter.mCurrentExpandedItem != null) {
   1546             state.expandedMenuItemId = mExpandedMenuPresenter.mCurrentExpandedItem.getItemId();
   1547         }
   1548 
   1549         state.isOverflowOpen = isOverflowMenuShowing();
   1550 
   1551         return state;
   1552     }
   1553 
   1554     @Override
   1555     protected void onRestoreInstanceState(Parcelable state) {
   1556         final SavedState ss = (SavedState) state;
   1557         super.onRestoreInstanceState(ss.getSuperState());
   1558 
   1559         final Menu menu = mMenuView != null ? mMenuView.peekMenu() : null;
   1560         if (ss.expandedMenuItemId != 0 && mExpandedMenuPresenter != null && menu != null) {
   1561             final MenuItem item = menu.findItem(ss.expandedMenuItemId);
   1562             if (item != null) {
   1563                 item.expandActionView();
   1564             }
   1565         }
   1566 
   1567         if (ss.isOverflowOpen) {
   1568             postShowOverflowMenu();
   1569         }
   1570     }
   1571 
   1572     private void postShowOverflowMenu() {
   1573         removeCallbacks(mShowOverflowMenuRunnable);
   1574         post(mShowOverflowMenuRunnable);
   1575     }
   1576 
   1577     @Override
   1578     protected void onDetachedFromWindow() {
   1579         super.onDetachedFromWindow();
   1580         removeCallbacks(mShowOverflowMenuRunnable);
   1581     }
   1582 
   1583     @Override
   1584     public boolean onTouchEvent(MotionEvent ev) {
   1585         // Toolbars always eat touch events, but should still respect the touch event dispatch
   1586         // contract. If the normal View implementation doesn't want the events, we'll just silently
   1587         // eat the rest of the gesture without reporting the events to the default implementation
   1588         // since that's what it expects.
   1589 
   1590         final int action = ev.getActionMasked();
   1591         if (action == MotionEvent.ACTION_DOWN) {
   1592             mEatingTouch = false;
   1593         }
   1594 
   1595         if (!mEatingTouch) {
   1596             final boolean handled = super.onTouchEvent(ev);
   1597             if (action == MotionEvent.ACTION_DOWN && !handled) {
   1598                 mEatingTouch = true;
   1599             }
   1600         }
   1601 
   1602         if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
   1603             mEatingTouch = false;
   1604         }
   1605 
   1606         return true;
   1607     }
   1608 
   1609     /**
   1610      * @hide
   1611      */
   1612     @Override
   1613     protected void onSetLayoutParams(View child, ViewGroup.LayoutParams lp) {
   1614         /*
   1615          * Apps may set ActionBar.LayoutParams on their action bar custom views when
   1616          * a Toolbar is actually acting in the role of the action bar. Perform a quick
   1617          * switch with Toolbar.LayoutParams whenever this happens. This does leave open
   1618          * one potential gotcha: if an app retains the ActionBar.LayoutParams reference
   1619          * and attempts to keep making changes to it before layout those changes won't
   1620          * be reflected in the final results.
   1621          */
   1622         if (!checkLayoutParams(lp)) {
   1623             child.setLayoutParams(generateLayoutParams(lp));
   1624         }
   1625     }
   1626 
   1627     private void measureChildConstrained(View child, int parentWidthSpec, int widthUsed,
   1628             int parentHeightSpec, int heightUsed, int heightConstraint) {
   1629         final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
   1630 
   1631         int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
   1632                 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
   1633                         + widthUsed, lp.width);
   1634         int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
   1635                 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
   1636                         + heightUsed, lp.height);
   1637 
   1638         final int childHeightMode = MeasureSpec.getMode(childHeightSpec);
   1639         if (childHeightMode != MeasureSpec.EXACTLY && heightConstraint >= 0) {
   1640             final int size = childHeightMode != MeasureSpec.UNSPECIFIED ?
   1641                     Math.min(MeasureSpec.getSize(childHeightSpec), heightConstraint) :
   1642                     heightConstraint;
   1643             childHeightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
   1644         }
   1645         child.measure(childWidthSpec, childHeightSpec);
   1646     }
   1647 
   1648     /**
   1649      * Returns the width + uncollapsed margins
   1650      */
   1651     private int measureChildCollapseMargins(View child,
   1652             int parentWidthMeasureSpec, int widthUsed,
   1653             int parentHeightMeasureSpec, int heightUsed, int[] collapsingMargins) {
   1654         final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
   1655 
   1656         final int leftDiff = lp.leftMargin - collapsingMargins[0];
   1657         final int rightDiff = lp.rightMargin - collapsingMargins[1];
   1658         final int leftMargin = Math.max(0, leftDiff);
   1659         final int rightMargin = Math.max(0, rightDiff);
   1660         final int hMargins = leftMargin + rightMargin;
   1661         collapsingMargins[0] = Math.max(0, -leftDiff);
   1662         collapsingMargins[1] = Math.max(0, -rightDiff);
   1663 
   1664         final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
   1665                 mPaddingLeft + mPaddingRight + hMargins + widthUsed, lp.width);
   1666         final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
   1667                 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
   1668                         + heightUsed, lp.height);
   1669 
   1670         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   1671         return child.getMeasuredWidth() + hMargins;
   1672     }
   1673 
   1674     /**
   1675      * Returns true if the Toolbar is collapsible and has no child views with a measured size > 0.
   1676      */
   1677     private boolean shouldCollapse() {
   1678         if (!mCollapsible) return false;
   1679 
   1680         final int childCount = getChildCount();
   1681         for (int i = 0; i < childCount; i++) {
   1682             final View child = getChildAt(i);
   1683             if (shouldLayout(child) && child.getMeasuredWidth() > 0 &&
   1684                     child.getMeasuredHeight() > 0) {
   1685                 return false;
   1686             }
   1687         }
   1688         return true;
   1689     }
   1690 
   1691     @Override
   1692     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   1693         int width = 0;
   1694         int height = 0;
   1695         int childState = 0;
   1696 
   1697         final int[] collapsingMargins = mTempMargins;
   1698         final int marginStartIndex;
   1699         final int marginEndIndex;
   1700         if (isLayoutRtl()) {
   1701             marginStartIndex = 1;
   1702             marginEndIndex = 0;
   1703         } else {
   1704             marginStartIndex = 0;
   1705             marginEndIndex = 1;
   1706         }
   1707 
   1708         // System views measure first.
   1709 
   1710         int navWidth = 0;
   1711         if (shouldLayout(mNavButtonView)) {
   1712             measureChildConstrained(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0,
   1713                     mMaxButtonHeight);
   1714             navWidth = mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
   1715             height = Math.max(height, mNavButtonView.getMeasuredHeight() +
   1716                     getVerticalMargins(mNavButtonView));
   1717             childState = combineMeasuredStates(childState, mNavButtonView.getMeasuredState());
   1718         }
   1719 
   1720         if (shouldLayout(mCollapseButtonView)) {
   1721             measureChildConstrained(mCollapseButtonView, widthMeasureSpec, width,
   1722                     heightMeasureSpec, 0, mMaxButtonHeight);
   1723             navWidth = mCollapseButtonView.getMeasuredWidth() +
   1724                     getHorizontalMargins(mCollapseButtonView);
   1725             height = Math.max(height, mCollapseButtonView.getMeasuredHeight() +
   1726                     getVerticalMargins(mCollapseButtonView));
   1727             childState = combineMeasuredStates(childState, mCollapseButtonView.getMeasuredState());
   1728         }
   1729 
   1730         final int contentInsetStart = getCurrentContentInsetStart();
   1731         width += Math.max(contentInsetStart, navWidth);
   1732         collapsingMargins[marginStartIndex] = Math.max(0, contentInsetStart - navWidth);
   1733 
   1734         int menuWidth = 0;
   1735         if (shouldLayout(mMenuView)) {
   1736             measureChildConstrained(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0,
   1737                     mMaxButtonHeight);
   1738             menuWidth = mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
   1739             height = Math.max(height, mMenuView.getMeasuredHeight() +
   1740                     getVerticalMargins(mMenuView));
   1741             childState = combineMeasuredStates(childState, mMenuView.getMeasuredState());
   1742         }
   1743 
   1744         final int contentInsetEnd = getCurrentContentInsetEnd();
   1745         width += Math.max(contentInsetEnd, menuWidth);
   1746         collapsingMargins[marginEndIndex] = Math.max(0, contentInsetEnd - menuWidth);
   1747 
   1748         if (shouldLayout(mExpandedActionView)) {
   1749             width += measureChildCollapseMargins(mExpandedActionView, widthMeasureSpec, width,
   1750                     heightMeasureSpec, 0, collapsingMargins);
   1751             height = Math.max(height, mExpandedActionView.getMeasuredHeight() +
   1752                     getVerticalMargins(mExpandedActionView));
   1753             childState = combineMeasuredStates(childState, mExpandedActionView.getMeasuredState());
   1754         }
   1755 
   1756         if (shouldLayout(mLogoView)) {
   1757             width += measureChildCollapseMargins(mLogoView, widthMeasureSpec, width,
   1758                     heightMeasureSpec, 0, collapsingMargins);
   1759             height = Math.max(height, mLogoView.getMeasuredHeight() +
   1760                     getVerticalMargins(mLogoView));
   1761             childState = combineMeasuredStates(childState, mLogoView.getMeasuredState());
   1762         }
   1763 
   1764         final int childCount = getChildCount();
   1765         for (int i = 0; i < childCount; i++) {
   1766             final View child = getChildAt(i);
   1767             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
   1768             if (lp.mViewType != LayoutParams.CUSTOM || !shouldLayout(child)) {
   1769                 // We already got all system views above. Skip them and GONE views.
   1770                 continue;
   1771             }
   1772 
   1773             width += measureChildCollapseMargins(child, widthMeasureSpec, width,
   1774                     heightMeasureSpec, 0, collapsingMargins);
   1775             height = Math.max(height, child.getMeasuredHeight() + getVerticalMargins(child));
   1776             childState = combineMeasuredStates(childState, child.getMeasuredState());
   1777         }
   1778 
   1779         int titleWidth = 0;
   1780         int titleHeight = 0;
   1781         final int titleVertMargins = mTitleMarginTop + mTitleMarginBottom;
   1782         final int titleHorizMargins = mTitleMarginStart + mTitleMarginEnd;
   1783         if (shouldLayout(mTitleTextView)) {
   1784             titleWidth = measureChildCollapseMargins(mTitleTextView, widthMeasureSpec,
   1785                     width + titleHorizMargins, heightMeasureSpec, titleVertMargins,
   1786                     collapsingMargins);
   1787             titleWidth = mTitleTextView.getMeasuredWidth() + getHorizontalMargins(mTitleTextView);
   1788             titleHeight = mTitleTextView.getMeasuredHeight() + getVerticalMargins(mTitleTextView);
   1789             childState = combineMeasuredStates(childState, mTitleTextView.getMeasuredState());
   1790         }
   1791         if (shouldLayout(mSubtitleTextView)) {
   1792             titleWidth = Math.max(titleWidth, measureChildCollapseMargins(mSubtitleTextView,
   1793                     widthMeasureSpec, width + titleHorizMargins,
   1794                     heightMeasureSpec, titleHeight + titleVertMargins,
   1795                     collapsingMargins));
   1796             titleHeight += mSubtitleTextView.getMeasuredHeight() +
   1797                     getVerticalMargins(mSubtitleTextView);
   1798             childState = combineMeasuredStates(childState, mSubtitleTextView.getMeasuredState());
   1799         }
   1800 
   1801         width += titleWidth;
   1802         height = Math.max(height, titleHeight);
   1803 
   1804         // Measurement already took padding into account for available space for the children,
   1805         // add it in for the final size.
   1806         width += getPaddingLeft() + getPaddingRight();
   1807         height += getPaddingTop() + getPaddingBottom();
   1808 
   1809         final int measuredWidth = resolveSizeAndState(
   1810                 Math.max(width, getSuggestedMinimumWidth()),
   1811                 widthMeasureSpec, childState & MEASURED_STATE_MASK);
   1812         final int measuredHeight = resolveSizeAndState(
   1813                 Math.max(height, getSuggestedMinimumHeight()),
   1814                 heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT);
   1815 
   1816         setMeasuredDimension(measuredWidth, shouldCollapse() ? 0 : measuredHeight);
   1817     }
   1818 
   1819     @Override
   1820     protected void onLayout(boolean changed, int l, int t, int r, int b) {
   1821         final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
   1822         final int width = getWidth();
   1823         final int height = getHeight();
   1824         final int paddingLeft = getPaddingLeft();
   1825         final int paddingRight = getPaddingRight();
   1826         final int paddingTop = getPaddingTop();
   1827         final int paddingBottom = getPaddingBottom();
   1828         int left = paddingLeft;
   1829         int right = width - paddingRight;
   1830 
   1831         final int[] collapsingMargins = mTempMargins;
   1832         collapsingMargins[0] = collapsingMargins[1] = 0;
   1833 
   1834         // Align views within the minimum toolbar height, if set.
   1835         final int minHeight = getMinimumHeight();
   1836         final int alignmentHeight = minHeight >= 0 ? Math.min(minHeight, b - t) : 0;
   1837 
   1838         if (shouldLayout(mNavButtonView)) {
   1839             if (isRtl) {
   1840                 right = layoutChildRight(mNavButtonView, right, collapsingMargins,
   1841                         alignmentHeight);
   1842             } else {
   1843                 left = layoutChildLeft(mNavButtonView, left, collapsingMargins,
   1844                         alignmentHeight);
   1845             }
   1846         }
   1847 
   1848         if (shouldLayout(mCollapseButtonView)) {
   1849             if (isRtl) {
   1850                 right = layoutChildRight(mCollapseButtonView, right, collapsingMargins,
   1851                         alignmentHeight);
   1852             } else {
   1853                 left = layoutChildLeft(mCollapseButtonView, left, collapsingMargins,
   1854                         alignmentHeight);
   1855             }
   1856         }
   1857 
   1858         if (shouldLayout(mMenuView)) {
   1859             if (isRtl) {
   1860                 left = layoutChildLeft(mMenuView, left, collapsingMargins,
   1861                         alignmentHeight);
   1862             } else {
   1863                 right = layoutChildRight(mMenuView, right, collapsingMargins,
   1864                         alignmentHeight);
   1865             }
   1866         }
   1867 
   1868         final int contentInsetLeft = getCurrentContentInsetLeft();
   1869         final int contentInsetRight = getCurrentContentInsetRight();
   1870         collapsingMargins[0] = Math.max(0, contentInsetLeft - left);
   1871         collapsingMargins[1] = Math.max(0, contentInsetRight - (width - paddingRight - right));
   1872         left = Math.max(left, contentInsetLeft);
   1873         right = Math.min(right, width - paddingRight - contentInsetRight);
   1874 
   1875         if (shouldLayout(mExpandedActionView)) {
   1876             if (isRtl) {
   1877                 right = layoutChildRight(mExpandedActionView, right, collapsingMargins,
   1878                         alignmentHeight);
   1879             } else {
   1880                 left = layoutChildLeft(mExpandedActionView, left, collapsingMargins,
   1881                         alignmentHeight);
   1882             }
   1883         }
   1884 
   1885         if (shouldLayout(mLogoView)) {
   1886             if (isRtl) {
   1887                 right = layoutChildRight(mLogoView, right, collapsingMargins,
   1888                         alignmentHeight);
   1889             } else {
   1890                 left = layoutChildLeft(mLogoView, left, collapsingMargins,
   1891                         alignmentHeight);
   1892             }
   1893         }
   1894 
   1895         final boolean layoutTitle = shouldLayout(mTitleTextView);
   1896         final boolean layoutSubtitle = shouldLayout(mSubtitleTextView);
   1897         int titleHeight = 0;
   1898         if (layoutTitle) {
   1899             final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
   1900             titleHeight += lp.topMargin + mTitleTextView.getMeasuredHeight() + lp.bottomMargin;
   1901         }
   1902         if (layoutSubtitle) {
   1903             final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams();
   1904             titleHeight += lp.topMargin + mSubtitleTextView.getMeasuredHeight() + lp.bottomMargin;
   1905         }
   1906 
   1907         if (layoutTitle || layoutSubtitle) {
   1908             int titleTop;
   1909             final View topChild = layoutTitle ? mTitleTextView : mSubtitleTextView;
   1910             final View bottomChild = layoutSubtitle ? mSubtitleTextView : mTitleTextView;
   1911             final LayoutParams toplp = (LayoutParams) topChild.getLayoutParams();
   1912             final LayoutParams bottomlp = (LayoutParams) bottomChild.getLayoutParams();
   1913             final boolean titleHasWidth = layoutTitle && mTitleTextView.getMeasuredWidth() > 0
   1914                     || layoutSubtitle && mSubtitleTextView.getMeasuredWidth() > 0;
   1915 
   1916             switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
   1917                 case Gravity.TOP:
   1918                     titleTop = getPaddingTop() + toplp.topMargin + mTitleMarginTop;
   1919                     break;
   1920                 default:
   1921                 case Gravity.CENTER_VERTICAL:
   1922                     final int space = height - paddingTop - paddingBottom;
   1923                     int spaceAbove = (space - titleHeight) / 2;
   1924                     if (spaceAbove < toplp.topMargin + mTitleMarginTop) {
   1925                         spaceAbove = toplp.topMargin + mTitleMarginTop;
   1926                     } else {
   1927                         final int spaceBelow = height - paddingBottom - titleHeight -
   1928                                 spaceAbove - paddingTop;
   1929                         if (spaceBelow < toplp.bottomMargin + mTitleMarginBottom) {
   1930                             spaceAbove = Math.max(0, spaceAbove -
   1931                                     (bottomlp.bottomMargin + mTitleMarginBottom - spaceBelow));
   1932                         }
   1933                     }
   1934                     titleTop = paddingTop + spaceAbove;
   1935                     break;
   1936                 case Gravity.BOTTOM:
   1937                     titleTop = height - paddingBottom - bottomlp.bottomMargin - mTitleMarginBottom -
   1938                             titleHeight;
   1939                     break;
   1940             }
   1941             if (isRtl) {
   1942                 final int rd = (titleHasWidth ? mTitleMarginStart : 0) - collapsingMargins[1];
   1943                 right -= Math.max(0, rd);
   1944                 collapsingMargins[1] = Math.max(0, -rd);
   1945                 int titleRight = right;
   1946                 int subtitleRight = right;
   1947 
   1948                 if (layoutTitle) {
   1949                     final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
   1950                     final int titleLeft = titleRight - mTitleTextView.getMeasuredWidth();
   1951                     final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
   1952                     mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
   1953                     titleRight = titleLeft - mTitleMarginEnd;
   1954                     titleTop = titleBottom + lp.bottomMargin;
   1955                 }
   1956                 if (layoutSubtitle) {
   1957                     final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams();
   1958                     titleTop += lp.topMargin;
   1959                     final int subtitleLeft = subtitleRight - mSubtitleTextView.getMeasuredWidth();
   1960                     final int subtitleBottom = titleTop + mSubtitleTextView.getMeasuredHeight();
   1961                     mSubtitleTextView.layout(subtitleLeft, titleTop, subtitleRight, subtitleBottom);
   1962                     subtitleRight = subtitleRight - mTitleMarginEnd;
   1963                     titleTop = subtitleBottom + lp.bottomMargin;
   1964                 }
   1965                 if (titleHasWidth) {
   1966                     right = Math.min(titleRight, subtitleRight);
   1967                 }
   1968             } else {
   1969                 final int ld = (titleHasWidth ? mTitleMarginStart : 0) - collapsingMargins[0];
   1970                 left += Math.max(0, ld);
   1971                 collapsingMargins[0] = Math.max(0, -ld);
   1972                 int titleLeft = left;
   1973                 int subtitleLeft = left;
   1974 
   1975                 if (layoutTitle) {
   1976                     final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
   1977                     final int titleRight = titleLeft + mTitleTextView.getMeasuredWidth();
   1978                     final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
   1979                     mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
   1980                     titleLeft = titleRight + mTitleMarginEnd;
   1981                     titleTop = titleBottom + lp.bottomMargin;
   1982                 }
   1983                 if (layoutSubtitle) {
   1984                     final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams();
   1985                     titleTop += lp.topMargin;
   1986                     final int subtitleRight = subtitleLeft + mSubtitleTextView.getMeasuredWidth();
   1987                     final int subtitleBottom = titleTop + mSubtitleTextView.getMeasuredHeight();
   1988                     mSubtitleTextView.layout(subtitleLeft, titleTop, subtitleRight, subtitleBottom);
   1989                     subtitleLeft = subtitleRight + mTitleMarginEnd;
   1990                     titleTop = subtitleBottom + lp.bottomMargin;
   1991                 }
   1992                 if (titleHasWidth) {
   1993                     left = Math.max(titleLeft, subtitleLeft);
   1994                 }
   1995             }
   1996         }
   1997 
   1998         // Get all remaining children sorted for layout. This is all prepared
   1999         // such that absolute layout direction can be used below.
   2000 
   2001         addCustomViewsWithGravity(mTempViews, Gravity.LEFT);
   2002         final int leftViewsCount = mTempViews.size();
   2003         for (int i = 0; i < leftViewsCount; i++) {
   2004             left = layoutChildLeft(mTempViews.get(i), left, collapsingMargins,
   2005                     alignmentHeight);
   2006         }
   2007 
   2008         addCustomViewsWithGravity(mTempViews, Gravity.RIGHT);
   2009         final int rightViewsCount = mTempViews.size();
   2010         for (int i = 0; i < rightViewsCount; i++) {
   2011             right = layoutChildRight(mTempViews.get(i), right, collapsingMargins,
   2012                     alignmentHeight);
   2013         }
   2014 
   2015         // Centered views try to center with respect to the whole bar, but views pinned
   2016         // to the left or right can push the mass of centered views to one side or the other.
   2017         addCustomViewsWithGravity(mTempViews, Gravity.CENTER_HORIZONTAL);
   2018         final int centerViewsWidth = getViewListMeasuredWidth(mTempViews, collapsingMargins);
   2019         final int parentCenter = paddingLeft + (width - paddingLeft - paddingRight) / 2;
   2020         final int halfCenterViewsWidth = centerViewsWidth / 2;
   2021         int centerLeft = parentCenter - halfCenterViewsWidth;
   2022         final int centerRight = centerLeft + centerViewsWidth;
   2023         if (centerLeft < left) {
   2024             centerLeft = left;
   2025         } else if (centerRight > right) {
   2026             centerLeft -= centerRight - right;
   2027         }
   2028 
   2029         final int centerViewsCount = mTempViews.size();
   2030         for (int i = 0; i < centerViewsCount; i++) {
   2031             centerLeft = layoutChildLeft(mTempViews.get(i), centerLeft, collapsingMargins,
   2032                     alignmentHeight);
   2033         }
   2034 
   2035         mTempViews.clear();
   2036     }
   2037 
   2038     private int getViewListMeasuredWidth(List<View> views, int[] collapsingMargins) {
   2039         int collapseLeft = collapsingMargins[0];
   2040         int collapseRight = collapsingMargins[1];
   2041         int width = 0;
   2042         final int count = views.size();
   2043         for (int i = 0; i < count; i++) {
   2044             final View v = views.get(i);
   2045             final LayoutParams lp = (LayoutParams) v.getLayoutParams();
   2046             final int l = lp.leftMargin - collapseLeft;
   2047             final int r = lp.rightMargin - collapseRight;
   2048             final int leftMargin = Math.max(0, l);
   2049             final int rightMargin = Math.max(0, r);
   2050             collapseLeft = Math.max(0, -l);
   2051             collapseRight = Math.max(0, -r);
   2052             width += leftMargin + v.getMeasuredWidth() + rightMargin;
   2053         }
   2054         return width;
   2055     }
   2056 
   2057     private int layoutChildLeft(View child, int left, int[] collapsingMargins,
   2058             int alignmentHeight) {
   2059         final LayoutParams lp = (LayoutParams) child.getLayoutParams();
   2060         final int l = lp.leftMargin - collapsingMargins[0];
   2061         left += Math.max(0, l);
   2062         collapsingMargins[0] = Math.max(0, -l);
   2063         final int top = getChildTop(child, alignmentHeight);
   2064         final int childWidth = child.getMeasuredWidth();
   2065         child.layout(left, top, left + childWidth, top + child.getMeasuredHeight());
   2066         left += childWidth + lp.rightMargin;
   2067         return left;
   2068     }
   2069 
   2070     private int layoutChildRight(View child, int right, int[] collapsingMargins,
   2071             int alignmentHeight) {
   2072         final LayoutParams lp = (LayoutParams) child.getLayoutParams();
   2073         final int r = lp.rightMargin - collapsingMargins[1];
   2074         right -= Math.max(0, r);
   2075         collapsingMargins[1] = Math.max(0, -r);
   2076         final int top = getChildTop(child, alignmentHeight);
   2077         final int childWidth = child.getMeasuredWidth();
   2078         child.layout(right - childWidth, top, right, top + child.getMeasuredHeight());
   2079         right -= childWidth + lp.leftMargin;
   2080         return right;
   2081     }
   2082 
   2083     private int getChildTop(View child, int alignmentHeight) {
   2084         final LayoutParams lp = (LayoutParams) child.getLayoutParams();
   2085         final int childHeight = child.getMeasuredHeight();
   2086         final int alignmentOffset = alignmentHeight > 0 ? (childHeight - alignmentHeight) / 2 : 0;
   2087         switch (getChildVerticalGravity(lp.gravity)) {
   2088             case Gravity.TOP:
   2089                 return getPaddingTop() - alignmentOffset;
   2090 
   2091             case Gravity.BOTTOM:
   2092                 return getHeight() - getPaddingBottom() - childHeight
   2093                         - lp.bottomMargin - alignmentOffset;
   2094 
   2095             default:
   2096             case Gravity.CENTER_VERTICAL:
   2097                 final int paddingTop = getPaddingTop();
   2098                 final int paddingBottom = getPaddingBottom();
   2099                 final int height = getHeight();
   2100                 final int space = height - paddingTop - paddingBottom;
   2101                 int spaceAbove = (space - childHeight) / 2;
   2102                 if (spaceAbove < lp.topMargin) {
   2103                     spaceAbove = lp.topMargin;
   2104                 } else {
   2105                     final int spaceBelow = height - paddingBottom - childHeight -
   2106                             spaceAbove - paddingTop;
   2107                     if (spaceBelow < lp.bottomMargin) {
   2108                         spaceAbove = Math.max(0, spaceAbove - (lp.bottomMargin - spaceBelow));
   2109                     }
   2110                 }
   2111                 return paddingTop + spaceAbove;
   2112         }
   2113     }
   2114 
   2115     private int getChildVerticalGravity(int gravity) {
   2116         final int vgrav = gravity & Gravity.VERTICAL_GRAVITY_MASK;
   2117         switch (vgrav) {
   2118             case Gravity.TOP:
   2119             case Gravity.BOTTOM:
   2120             case Gravity.CENTER_VERTICAL:
   2121                 return vgrav;
   2122             default:
   2123                 return mGravity & Gravity.VERTICAL_GRAVITY_MASK;
   2124         }
   2125     }
   2126 
   2127     /**
   2128      * Prepare a list of non-SYSTEM child views. If the layout direction is RTL
   2129      * this will be in reverse child order.
   2130      *
   2131      * @param views List to populate. It will be cleared before use.
   2132      * @param gravity Horizontal gravity to match against
   2133      */
   2134     private void addCustomViewsWithGravity(List<View> views, int gravity) {
   2135         final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
   2136         final int childCount = getChildCount();
   2137         final int absGrav = Gravity.getAbsoluteGravity(gravity, getLayoutDirection());
   2138 
   2139         views.clear();
   2140 
   2141         if (isRtl) {
   2142             for (int i = childCount - 1; i >= 0; i--) {
   2143                 final View child = getChildAt(i);
   2144                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
   2145                 if (lp.mViewType == LayoutParams.CUSTOM && shouldLayout(child) &&
   2146                         getChildHorizontalGravity(lp.gravity) == absGrav) {
   2147                     views.add(child);
   2148                 }
   2149             }
   2150         } else {
   2151             for (int i = 0; i < childCount; i++) {
   2152                 final View child = getChildAt(i);
   2153                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
   2154                 if (lp.mViewType == LayoutParams.CUSTOM && shouldLayout(child) &&
   2155                         getChildHorizontalGravity(lp.gravity) == absGrav) {
   2156                     views.add(child);
   2157                 }
   2158             }
   2159         }
   2160     }
   2161 
   2162     private int getChildHorizontalGravity(int gravity) {
   2163         final int ld = getLayoutDirection();
   2164         final int absGrav = Gravity.getAbsoluteGravity(gravity, ld);
   2165         final int hGrav = absGrav & Gravity.HORIZONTAL_GRAVITY_MASK;
   2166         switch (hGrav) {
   2167             case Gravity.LEFT:
   2168             case Gravity.RIGHT:
   2169             case Gravity.CENTER_HORIZONTAL:
   2170                 return hGrav;
   2171             default:
   2172                 return ld == LAYOUT_DIRECTION_RTL ? Gravity.RIGHT : Gravity.LEFT;
   2173         }
   2174     }
   2175 
   2176     private boolean shouldLayout(View view) {
   2177         return view != null && view.getParent() == this && view.getVisibility() != GONE;
   2178     }
   2179 
   2180     private int getHorizontalMargins(View v) {
   2181         final MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
   2182         return mlp.getMarginStart() + mlp.getMarginEnd();
   2183     }
   2184 
   2185     private int getVerticalMargins(View v) {
   2186         final MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
   2187         return mlp.topMargin + mlp.bottomMargin;
   2188     }
   2189 
   2190     @Override
   2191     public LayoutParams generateLayoutParams(AttributeSet attrs) {
   2192         return new LayoutParams(getContext(), attrs);
   2193     }
   2194 
   2195     @Override
   2196     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
   2197         if (p instanceof LayoutParams) {
   2198             return new LayoutParams((LayoutParams) p);
   2199         } else if (p instanceof ActionBar.LayoutParams) {
   2200             return new LayoutParams((ActionBar.LayoutParams) p);
   2201         } else if (p instanceof MarginLayoutParams) {
   2202             return new LayoutParams((MarginLayoutParams) p);
   2203         } else {
   2204             return new LayoutParams(p);
   2205         }
   2206     }
   2207 
   2208     @Override
   2209     protected LayoutParams generateDefaultLayoutParams() {
   2210         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
   2211     }
   2212 
   2213     @Override
   2214     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
   2215         return super.checkLayoutParams(p) && p instanceof LayoutParams;
   2216     }
   2217 
   2218     private static boolean isCustomView(View child) {
   2219         return ((LayoutParams) child.getLayoutParams()).mViewType == LayoutParams.CUSTOM;
   2220     }
   2221 
   2222     /** @hide */
   2223     public DecorToolbar getWrapper() {
   2224         if (mWrapper == null) {
   2225             mWrapper = new ToolbarWidgetWrapper(this, true);
   2226         }
   2227         return mWrapper;
   2228     }
   2229 
   2230     void removeChildrenForExpandedActionView() {
   2231         final int childCount = getChildCount();
   2232         // Go backwards since we're removing from the list
   2233         for (int i = childCount - 1; i >= 0; i--) {
   2234             final View child = getChildAt(i);
   2235             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
   2236             if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) {
   2237                 removeViewAt(i);
   2238                 mHiddenViews.add(child);
   2239             }
   2240         }
   2241     }
   2242 
   2243     void addChildrenForExpandedActionView() {
   2244         final int count = mHiddenViews.size();
   2245         // Re-add in reverse order since we removed in reverse order
   2246         for (int i = count - 1; i >= 0; i--) {
   2247             addView(mHiddenViews.get(i));
   2248         }
   2249         mHiddenViews.clear();
   2250     }
   2251 
   2252     private boolean isChildOrHidden(View child) {
   2253         return child.getParent() == this || mHiddenViews.contains(child);
   2254     }
   2255 
   2256     /**
   2257      * Force the toolbar to collapse to zero-height during measurement if
   2258      * it could be considered "empty" (no visible elements with nonzero measured size)
   2259      * @hide
   2260      */
   2261     public void setCollapsible(boolean collapsible) {
   2262         mCollapsible = collapsible;
   2263         requestLayout();
   2264     }
   2265 
   2266     /**
   2267      * Must be called before the menu is accessed
   2268      * @hide
   2269      */
   2270     public void setMenuCallbacks(MenuPresenter.Callback pcb, MenuBuilder.Callback mcb) {
   2271         mActionMenuPresenterCallback = pcb;
   2272         mMenuBuilderCallback = mcb;
   2273         if (mMenuView != null) {
   2274             mMenuView.setMenuCallbacks(pcb, mcb);
   2275         }
   2276     }
   2277 
   2278     private void ensureContentInsets() {
   2279         if (mContentInsets == null) {
   2280             mContentInsets = new RtlSpacingHelper();
   2281         }
   2282     }
   2283 
   2284     /**
   2285      * Accessor to enable LayoutLib to get ActionMenuPresenter directly.
   2286      */
   2287     ActionMenuPresenter getOuterActionMenuPresenter() {
   2288         return mOuterActionMenuPresenter;
   2289     }
   2290 
   2291     Context getPopupContext() {
   2292         return mPopupContext;
   2293     }
   2294 
   2295     /**
   2296      * Interface responsible for receiving menu item click events if the items themselves
   2297      * do not have individual item click listeners.
   2298      */
   2299     public interface OnMenuItemClickListener {
   2300         /**
   2301          * This method will be invoked when a menu item is clicked if the item itself did
   2302          * not already handle the event.
   2303          *
   2304          * @param item {@link MenuItem} that was clicked
   2305          * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
   2306          */
   2307         public boolean onMenuItemClick(MenuItem item);
   2308     }
   2309 
   2310     /**
   2311      * Layout information for child views of Toolbars.
   2312      *
   2313      * <p>Toolbar.LayoutParams extends ActionBar.LayoutParams for compatibility with existing
   2314      * ActionBar API. See {@link android.app.Activity#setActionBar(Toolbar) Activity.setActionBar}
   2315      * for more info on how to use a Toolbar as your Activity's ActionBar.</p>
   2316      *
   2317      * @attr ref android.R.styleable#Toolbar_LayoutParams_layout_gravity
   2318      */
   2319     public static class LayoutParams extends ActionBar.LayoutParams {
   2320         static final int CUSTOM = 0;
   2321         static final int SYSTEM = 1;
   2322         static final int EXPANDED = 2;
   2323 
   2324         int mViewType = CUSTOM;
   2325 
   2326         public LayoutParams(@NonNull Context c, AttributeSet attrs) {
   2327             super(c, attrs);
   2328         }
   2329 
   2330         public LayoutParams(int width, int height) {
   2331             super(width, height);
   2332             this.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
   2333         }
   2334 
   2335         public LayoutParams(int width, int height, int gravity) {
   2336             super(width, height);
   2337             this.gravity = gravity;
   2338         }
   2339 
   2340         public LayoutParams(int gravity) {
   2341             this(WRAP_CONTENT, MATCH_PARENT, gravity);
   2342         }
   2343 
   2344         public LayoutParams(LayoutParams source) {
   2345             super(source);
   2346 
   2347             mViewType = source.mViewType;
   2348         }
   2349 
   2350         public LayoutParams(ActionBar.LayoutParams source) {
   2351             super(source);
   2352         }
   2353 
   2354         public LayoutParams(MarginLayoutParams source) {
   2355             super(source);
   2356             // ActionBar.LayoutParams doesn't have a MarginLayoutParams constructor.
   2357             // Fake it here and copy over the relevant data.
   2358             copyMarginsFrom(source);
   2359         }
   2360 
   2361         public LayoutParams(ViewGroup.LayoutParams source) {
   2362             super(source);
   2363         }
   2364     }
   2365 
   2366     static class SavedState extends BaseSavedState {
   2367         public int expandedMenuItemId;
   2368         public boolean isOverflowOpen;
   2369 
   2370         public SavedState(Parcel source) {
   2371             super(source);
   2372             expandedMenuItemId = source.readInt();
   2373             isOverflowOpen = source.readInt() != 0;
   2374         }
   2375 
   2376         public SavedState(Parcelable superState) {
   2377             super(superState);
   2378         }
   2379 
   2380         @Override
   2381         public void writeToParcel(Parcel out, int flags) {
   2382             super.writeToParcel(out, flags);
   2383             out.writeInt(expandedMenuItemId);
   2384             out.writeInt(isOverflowOpen ? 1 : 0);
   2385         }
   2386 
   2387         public static final @android.annotation.NonNull Creator<SavedState> CREATOR = new Creator<SavedState>() {
   2388 
   2389             @Override
   2390             public SavedState createFromParcel(Parcel source) {
   2391                 return new SavedState(source);
   2392             }
   2393 
   2394             @Override
   2395             public SavedState[] newArray(int size) {
   2396                 return new SavedState[size];
   2397             }
   2398         };
   2399     }
   2400 
   2401     private class ExpandedActionViewMenuPresenter implements MenuPresenter {
   2402         MenuBuilder mMenu;
   2403         MenuItemImpl mCurrentExpandedItem;
   2404 
   2405         @Override
   2406         public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
   2407             // Clear the expanded action view when menus change.
   2408             if (mMenu != null && mCurrentExpandedItem != null) {
   2409                 mMenu.collapseItemActionView(mCurrentExpandedItem);
   2410             }
   2411             mMenu = menu;
   2412         }
   2413 
   2414         @Override
   2415         public MenuView getMenuView(ViewGroup root) {
   2416             return null;
   2417         }
   2418 
   2419         @Override
   2420         public void updateMenuView(boolean cleared) {
   2421             // Make sure the expanded item we have is still there.
   2422             if (mCurrentExpandedItem != null) {
   2423                 boolean found = false;
   2424 
   2425                 if (mMenu != null) {
   2426                     final int count = mMenu.size();
   2427                     for (int i = 0; i < count; i++) {
   2428                         final MenuItem item = mMenu.getItem(i);
   2429                         if (item == mCurrentExpandedItem) {
   2430                             found = true;
   2431                             break;
   2432                         }
   2433                     }
   2434                 }
   2435 
   2436                 if (!found) {
   2437                     // The item we had expanded disappeared. Collapse.
   2438                     collapseItemActionView(mMenu, mCurrentExpandedItem);
   2439                 }
   2440             }
   2441         }
   2442 
   2443         @Override
   2444         public void setCallback(Callback cb) {
   2445         }
   2446 
   2447         @Override
   2448         public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
   2449             return false;
   2450         }
   2451 
   2452         @Override
   2453         public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
   2454         }
   2455 
   2456         @Override
   2457         public boolean flagActionItems() {
   2458             return false;
   2459         }
   2460 
   2461         @Override
   2462         public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
   2463             ensureCollapseButtonView();
   2464             if (mCollapseButtonView.getParent() != Toolbar.this) {
   2465                 addView(mCollapseButtonView);
   2466             }
   2467             mExpandedActionView = item.getActionView();
   2468             mCurrentExpandedItem = item;
   2469             if (mExpandedActionView.getParent() != Toolbar.this) {
   2470                 final LayoutParams lp = generateDefaultLayoutParams();
   2471                 lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
   2472                 lp.mViewType = LayoutParams.EXPANDED;
   2473                 mExpandedActionView.setLayoutParams(lp);
   2474                 addView(mExpandedActionView);
   2475             }
   2476 
   2477             removeChildrenForExpandedActionView();
   2478             requestLayout();
   2479             item.setActionViewExpanded(true);
   2480 
   2481             if (mExpandedActionView instanceof CollapsibleActionView) {
   2482                 ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
   2483             }
   2484 
   2485             return true;
   2486         }
   2487 
   2488         @Override
   2489         public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
   2490             // Do this before detaching the actionview from the hierarchy, in case
   2491             // it needs to dismiss the soft keyboard, etc.
   2492             if (mExpandedActionView instanceof CollapsibleActionView) {
   2493                 ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed();
   2494             }
   2495 
   2496             removeView(mExpandedActionView);
   2497             removeView(mCollapseButtonView);
   2498             mExpandedActionView = null;
   2499 
   2500             addChildrenForExpandedActionView();
   2501             mCurrentExpandedItem = null;
   2502             requestLayout();
   2503             item.setActionViewExpanded(false);
   2504 
   2505             return true;
   2506         }
   2507 
   2508         @Override
   2509         public int getId() {
   2510             return 0;
   2511         }
   2512 
   2513         @Override
   2514         public Parcelable onSaveInstanceState() {
   2515             return null;
   2516         }
   2517 
   2518         @Override
   2519         public void onRestoreInstanceState(Parcelable state) {
   2520         }
   2521     }
   2522 }
   2523