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