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