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