ActionBarOverlayLayout.java revision ac5fe7c617c66850fff75a9fce9979c6e5674b0f
1/*
2 * Copyright (C) 2012 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
17package androidx.appcompat.widget;
18
19import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
20
21import android.animation.Animator;
22import android.animation.AnimatorListenerAdapter;
23import android.content.Context;
24import android.content.res.Configuration;
25import android.content.res.TypedArray;
26import android.graphics.Canvas;
27import android.graphics.Rect;
28import android.graphics.drawable.Drawable;
29import android.os.Build;
30import android.os.Parcelable;
31import androidx.annotation.RestrictTo;
32import androidx.core.view.NestedScrollingParent;
33import androidx.core.view.NestedScrollingParentHelper;
34import androidx.core.view.ViewCompat;
35import androidx.appcompat.app.AppCompatDelegate;
36import androidx.appcompat.R;
37import androidx.appcompat.view.menu.MenuPresenter;
38import android.util.AttributeSet;
39import android.util.SparseArray;
40import android.view.Menu;
41import android.view.View;
42import android.view.ViewGroup;
43import android.view.ViewPropertyAnimator;
44import android.view.Window;
45import android.widget.OverScroller;
46
47/**
48 * Special layout for the containing of an overlay action bar (and its content) to correctly handle
49 * fitting system windows when the content has request that its layout ignore them.
50 *
51 * @hide
52 */
53@RestrictTo(LIBRARY_GROUP)
54public class ActionBarOverlayLayout extends ViewGroup implements DecorContentParent,
55        NestedScrollingParent {
56    private static final String TAG = "ActionBarOverlayLayout";
57
58    private int mActionBarHeight;
59    //private WindowDecorActionBar mActionBar;
60    private int mWindowVisibility = View.VISIBLE;
61
62    // The main UI elements that we handle the layout of.
63    private ContentFrameLayout mContent;
64    ActionBarContainer mActionBarTop;
65
66    // Some interior UI elements.
67    private DecorToolbar mDecorToolbar;
68
69    // Content overlay drawable - generally the action bar's shadow
70    private Drawable mWindowContentOverlay;
71    private boolean mIgnoreWindowContentOverlay;
72
73    private boolean mOverlayMode;
74    private boolean mHasNonEmbeddedTabs;
75    private boolean mHideOnContentScroll;
76    boolean mAnimatingForFling;
77    private int mHideOnContentScrollReference;
78    private int mLastSystemUiVisibility;
79    private final Rect mBaseContentInsets = new Rect();
80    private final Rect mLastBaseContentInsets = new Rect();
81    private final Rect mContentInsets = new Rect();
82    private final Rect mBaseInnerInsets = new Rect();
83    private final Rect mLastBaseInnerInsets = new Rect();
84    private final Rect mInnerInsets = new Rect();
85    private final Rect mLastInnerInsets = new Rect();
86
87    private ActionBarVisibilityCallback mActionBarVisibilityCallback;
88
89    private static final int ACTION_BAR_ANIMATE_DELAY = 600; // ms
90
91    private OverScroller mFlingEstimator;
92
93    ViewPropertyAnimator mCurrentActionBarTopAnimator;
94
95    final AnimatorListenerAdapter mTopAnimatorListener = new AnimatorListenerAdapter() {
96        @Override
97        public void onAnimationEnd(Animator animator) {
98            mCurrentActionBarTopAnimator = null;
99            mAnimatingForFling = false;
100        }
101
102        @Override
103        public void onAnimationCancel(Animator animator) {
104            mCurrentActionBarTopAnimator = null;
105            mAnimatingForFling = false;
106        }
107    };
108
109    private final Runnable mRemoveActionBarHideOffset = new Runnable() {
110        @Override
111        public void run() {
112            haltActionBarHideOffsetAnimations();
113            mCurrentActionBarTopAnimator = mActionBarTop.animate().translationY(0)
114                    .setListener(mTopAnimatorListener);
115        }
116    };
117
118    private final Runnable mAddActionBarHideOffset = new Runnable() {
119        @Override
120        public void run() {
121            haltActionBarHideOffsetAnimations();
122            mCurrentActionBarTopAnimator = mActionBarTop.animate()
123                    .translationY(-mActionBarTop.getHeight())
124                    .setListener(mTopAnimatorListener);
125        }
126    };
127
128    static final int[] ATTRS = new int [] {
129            R.attr.actionBarSize,
130            android.R.attr.windowContentOverlay
131    };
132
133    private final NestedScrollingParentHelper mParentHelper;
134
135    public ActionBarOverlayLayout(Context context) {
136        this(context, null);
137    }
138
139    public ActionBarOverlayLayout(Context context, AttributeSet attrs) {
140        super(context, attrs);
141        init(context);
142
143        mParentHelper = new NestedScrollingParentHelper(this);
144    }
145
146    private void init(Context context) {
147        TypedArray ta = getContext().getTheme().obtainStyledAttributes(ATTRS);
148        mActionBarHeight = ta.getDimensionPixelSize(0, 0);
149        mWindowContentOverlay = ta.getDrawable(1);
150        setWillNotDraw(mWindowContentOverlay == null);
151        ta.recycle();
152
153        mIgnoreWindowContentOverlay = context.getApplicationInfo().targetSdkVersion <
154                Build.VERSION_CODES.KITKAT;
155
156        mFlingEstimator = new OverScroller(context);
157    }
158
159    @Override
160    protected void onDetachedFromWindow() {
161        super.onDetachedFromWindow();
162        haltActionBarHideOffsetAnimations();
163    }
164
165    public void setActionBarVisibilityCallback(ActionBarVisibilityCallback cb) {
166        mActionBarVisibilityCallback = cb;
167        if (getWindowToken() != null) {
168            // This is being initialized after being added to a window;
169            // make sure to update all state now.
170            mActionBarVisibilityCallback.onWindowVisibilityChanged(mWindowVisibility);
171            if (mLastSystemUiVisibility != 0) {
172                int newVis = mLastSystemUiVisibility;
173                onWindowSystemUiVisibilityChanged(newVis);
174                ViewCompat.requestApplyInsets(this);
175            }
176        }
177    }
178
179    public void setOverlayMode(boolean overlayMode) {
180        mOverlayMode = overlayMode;
181
182        /*
183         * Drawing the window content overlay was broken before K so starting to draw it
184         * again unexpectedly will cause artifacts in some apps. They should fix it.
185         */
186        mIgnoreWindowContentOverlay = overlayMode &&
187                getContext().getApplicationInfo().targetSdkVersion <
188                        Build.VERSION_CODES.KITKAT;
189    }
190
191    public boolean isInOverlayMode() {
192        return mOverlayMode;
193    }
194
195    public void setHasNonEmbeddedTabs(boolean hasNonEmbeddedTabs) {
196        mHasNonEmbeddedTabs = hasNonEmbeddedTabs;
197    }
198
199    public void setShowingForActionMode(boolean showing) {
200        // TODO: Add workaround for this
201//        if (showing) {
202//            // Here's a fun hack: if the status bar is currently being hidden,
203//            // and the application has asked for stable content insets, then
204//            // we will end up with the action mode action bar being shown
205//            // without the status bar, but moved below where the status bar
206//            // would be.  Not nice.  Trying to have this be positioned
207//            // correctly is not easy (basically we need yet *another* content
208//            // inset from the window manager to know where to put it), so
209//            // instead we will just temporarily force the status bar to be shown.
210//            if ((getWindowSystemUiVisibility() & (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
211//                    | SYSTEM_UI_FLAG_LAYOUT_STABLE))
212//                    == (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_STABLE)) {
213//                setDisabledSystemUiVisibility(SYSTEM_UI_FLAG_FULLSCREEN);
214//            }
215//        } else {
216//            setDisabledSystemUiVisibility(0);
217//        }
218    }
219
220    @Override
221    protected void onConfigurationChanged(Configuration newConfig) {
222        super.onConfigurationChanged(newConfig);
223        init(getContext());
224        ViewCompat.requestApplyInsets(this);
225    }
226
227    @Override
228    public void onWindowSystemUiVisibilityChanged(int visible) {
229        if (Build.VERSION.SDK_INT >= 16) {
230            super.onWindowSystemUiVisibilityChanged(visible);
231        }
232        pullChildren();
233        final int diff = mLastSystemUiVisibility ^ visible;
234        mLastSystemUiVisibility = visible;
235        final boolean barVisible = (visible & SYSTEM_UI_FLAG_FULLSCREEN) == 0;
236        final boolean stable = (visible & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
237        if (mActionBarVisibilityCallback != null) {
238            // We want the bar to be visible if it is not being hidden,
239            // or the app has not turned on a stable UI mode (meaning they
240            // are performing explicit layout around the action bar).
241            mActionBarVisibilityCallback.enableContentAnimations(!stable);
242            if (barVisible || !stable) mActionBarVisibilityCallback.showForSystem();
243            else mActionBarVisibilityCallback.hideForSystem();
244        }
245        if ((diff & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
246            if (mActionBarVisibilityCallback != null) {
247                ViewCompat.requestApplyInsets(this);
248            }
249        }
250    }
251
252    @Override
253    protected void onWindowVisibilityChanged(int visibility) {
254        super.onWindowVisibilityChanged(visibility);
255        mWindowVisibility = visibility;
256        if (mActionBarVisibilityCallback != null) {
257            mActionBarVisibilityCallback.onWindowVisibilityChanged(visibility);
258        }
259    }
260
261    private boolean applyInsets(View view, Rect insets, boolean left, boolean top,
262            boolean bottom, boolean right) {
263        boolean changed = false;
264        LayoutParams lp = (LayoutParams)view.getLayoutParams();
265        if (left && lp.leftMargin != insets.left) {
266            changed = true;
267            lp.leftMargin = insets.left;
268        }
269        if (top && lp.topMargin != insets.top) {
270            changed = true;
271            lp.topMargin = insets.top;
272        }
273        if (right && lp.rightMargin != insets.right) {
274            changed = true;
275            lp.rightMargin = insets.right;
276        }
277        if (bottom && lp.bottomMargin != insets.bottom) {
278            changed = true;
279            lp.bottomMargin = insets.bottom;
280        }
281        return changed;
282    }
283
284    @Override
285    protected boolean fitSystemWindows(Rect insets) {
286        pullChildren();
287
288        final int vis = ViewCompat.getWindowSystemUiVisibility(this);
289        final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
290        final Rect systemInsets = insets;
291
292        // The top action bar is always within the content area.
293        boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
294
295        mBaseInnerInsets.set(systemInsets);
296        ViewUtils.computeFitSystemWindows(this, mBaseInnerInsets, mBaseContentInsets);
297        if (!mLastBaseInnerInsets.equals(mBaseInnerInsets)) {
298            changed = true;
299            mLastBaseInnerInsets.set(mBaseInnerInsets);
300        }
301        if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
302            changed = true;
303            mLastBaseContentInsets.set(mBaseContentInsets);
304        }
305
306        if (changed) {
307            requestLayout();
308        }
309
310        // We don't do any more at this point.  To correctly compute the content/inner
311        // insets in all cases, we need to know the measured size of the various action
312        // bar elements. fitSystemWindows() happens before the measure pass, so we can't
313        // do that here. Instead we will take this up in onMeasure().
314        return true;
315    }
316
317    @Override
318    protected LayoutParams generateDefaultLayoutParams() {
319        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
320    }
321
322    @Override
323    public LayoutParams generateLayoutParams(AttributeSet attrs) {
324        return new LayoutParams(getContext(), attrs);
325    }
326
327    @Override
328    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
329        return new LayoutParams(p);
330    }
331
332    @Override
333    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
334        return p instanceof LayoutParams;
335    }
336
337    @Override
338    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
339        pullChildren();
340
341        int maxHeight = 0;
342        int maxWidth = 0;
343        int childState = 0;
344
345        int topInset = 0;
346        int bottomInset = 0;
347
348        measureChildWithMargins(mActionBarTop, widthMeasureSpec, 0, heightMeasureSpec, 0);
349        LayoutParams lp = (LayoutParams) mActionBarTop.getLayoutParams();
350        maxWidth = Math.max(maxWidth,
351                mActionBarTop.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
352        maxHeight = Math.max(maxHeight,
353                mActionBarTop.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
354        childState = View.combineMeasuredStates(childState, mActionBarTop.getMeasuredState());
355
356        final int vis = ViewCompat.getWindowSystemUiVisibility(this);
357        final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
358
359        if (stable) {
360            // This is the standard space needed for the action bar.  For stable measurement,
361            // we can't depend on the size currently reported by it -- this must remain constant.
362            topInset = mActionBarHeight;
363            if (mHasNonEmbeddedTabs) {
364                final View tabs = mActionBarTop.getTabContainer();
365                if (tabs != null) {
366                    // If tabs are not embedded, increase space on top to account for them.
367                    topInset += mActionBarHeight;
368                }
369            }
370        } else if (mActionBarTop.getVisibility() != GONE) {
371            // This is the space needed on top of the window for all of the action bar
372            // and tabs.
373            topInset = mActionBarTop.getMeasuredHeight();
374        }
375
376        // If the window has not requested system UI layout flags, we need to
377        // make sure its content is not being covered by system UI...  though it
378        // will still be covered by the action bar if they have requested it to
379        // overlay.
380        mContentInsets.set(mBaseContentInsets);
381        mInnerInsets.set(mBaseInnerInsets);
382        if (!mOverlayMode && !stable) {
383            mContentInsets.top += topInset;
384            mContentInsets.bottom += bottomInset;
385        } else {
386            mInnerInsets.top += topInset;
387            mInnerInsets.bottom += bottomInset;
388        }
389        applyInsets(mContent, mContentInsets, true, true, true, true);
390
391        if (!mLastInnerInsets.equals(mInnerInsets)) {
392            // If the inner insets have changed, we need to dispatch this down to
393            // the app's fitSystemWindows().  We do this before measuring the content
394            // view to keep the same semantics as the normal fitSystemWindows() call.
395            mLastInnerInsets.set(mInnerInsets);
396
397            mContent.dispatchFitSystemWindows(mInnerInsets);
398        }
399
400        measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);
401        lp = (LayoutParams) mContent.getLayoutParams();
402        maxWidth = Math.max(maxWidth,
403                mContent.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
404        maxHeight = Math.max(maxHeight,
405                mContent.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
406        childState = View.combineMeasuredStates(childState, mContent.getMeasuredState());
407
408        // Account for padding too
409        maxWidth += getPaddingLeft() + getPaddingRight();
410        maxHeight += getPaddingTop() + getPaddingBottom();
411
412        // Check against our minimum height and width
413        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
414        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
415
416        setMeasuredDimension(
417                View.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
418                View.resolveSizeAndState(maxHeight, heightMeasureSpec,
419                        childState << MEASURED_HEIGHT_STATE_SHIFT));
420    }
421
422    @Override
423    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
424        final int count = getChildCount();
425
426        final int parentLeft = getPaddingLeft();
427        final int parentRight = right - left - getPaddingRight();
428
429        final int parentTop = getPaddingTop();
430        final int parentBottom = bottom - top - getPaddingBottom();
431
432        for (int i = 0; i < count; i++) {
433            final View child = getChildAt(i);
434            if (child.getVisibility() != GONE) {
435                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
436
437                final int width = child.getMeasuredWidth();
438                final int height = child.getMeasuredHeight();
439
440                int childLeft = parentLeft + lp.leftMargin;
441                int childTop = parentTop + lp.topMargin;
442
443                child.layout(childLeft, childTop, childLeft + width, childTop + height);
444            }
445        }
446    }
447
448    @Override
449    public void draw(Canvas c) {
450        super.draw(c);
451        if (mWindowContentOverlay != null && !mIgnoreWindowContentOverlay) {
452            final int top = mActionBarTop.getVisibility() == VISIBLE ?
453                    (int) (mActionBarTop.getBottom() + mActionBarTop.getTranslationY() + 0.5f)
454                    : 0;
455            mWindowContentOverlay.setBounds(0, top, getWidth(),
456                    top + mWindowContentOverlay.getIntrinsicHeight());
457            mWindowContentOverlay.draw(c);
458        }
459    }
460
461    @Override
462    public boolean shouldDelayChildPressedState() {
463        return false;
464    }
465
466    @Override
467    public boolean onStartNestedScroll(View child, View target, int axes) {
468        if ((axes & SCROLL_AXIS_VERTICAL) == 0 || mActionBarTop.getVisibility() != VISIBLE) {
469            return false;
470        }
471        return mHideOnContentScroll;
472    }
473
474    @Override
475    public void onNestedScrollAccepted(View child, View target, int axes) {
476        mParentHelper.onNestedScrollAccepted(child, target, axes);
477        mHideOnContentScrollReference = getActionBarHideOffset();
478        haltActionBarHideOffsetAnimations();
479        if (mActionBarVisibilityCallback != null) {
480            mActionBarVisibilityCallback.onContentScrollStarted();
481        }
482    }
483
484    @Override
485    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
486            int dxUnconsumed, int dyUnconsumed) {
487        mHideOnContentScrollReference += dyConsumed;
488        setActionBarHideOffset(mHideOnContentScrollReference);
489    }
490
491    @Override
492    public void onStopNestedScroll(View target) {
493        if (mHideOnContentScroll && !mAnimatingForFling) {
494            if (mHideOnContentScrollReference <= mActionBarTop.getHeight()) {
495                postRemoveActionBarHideOffset();
496            } else {
497                postAddActionBarHideOffset();
498            }
499        }
500        if (mActionBarVisibilityCallback != null) {
501            mActionBarVisibilityCallback.onContentScrollStopped();
502        }
503    }
504
505    @Override
506    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
507        if (!mHideOnContentScroll || !consumed) {
508            return false;
509        }
510        if (shouldHideActionBarOnFling(velocityX, velocityY)) {
511            addActionBarHideOffset();
512        } else {
513            removeActionBarHideOffset();
514        }
515        mAnimatingForFling = true;
516        return true;
517    }
518
519    @Override
520    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
521        // no-op
522    }
523
524    @Override
525    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
526        return false;
527    }
528
529    @Override
530    public int getNestedScrollAxes() {
531        return mParentHelper.getNestedScrollAxes();
532    }
533
534    void pullChildren() {
535        if (mContent == null) {
536            mContent = findViewById(R.id.action_bar_activity_content);
537            mActionBarTop = findViewById(R.id.action_bar_container);
538            mDecorToolbar = getDecorToolbar(findViewById(R.id.action_bar));
539        }
540    }
541
542    private DecorToolbar getDecorToolbar(View view) {
543        if (view instanceof DecorToolbar) {
544            return (DecorToolbar) view;
545        } else if (view instanceof Toolbar) {
546            return ((Toolbar) view).getWrapper();
547        } else {
548            throw new IllegalStateException("Can't make a decor toolbar out of " +
549                    view.getClass().getSimpleName());
550        }
551    }
552
553    public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
554        if (hideOnContentScroll != mHideOnContentScroll) {
555            mHideOnContentScroll = hideOnContentScroll;
556            if (!hideOnContentScroll) {
557                haltActionBarHideOffsetAnimations();
558                setActionBarHideOffset(0);
559            }
560        }
561    }
562
563    public boolean isHideOnContentScrollEnabled() {
564        return mHideOnContentScroll;
565    }
566
567    public int getActionBarHideOffset() {
568        return mActionBarTop != null ? -((int) mActionBarTop.getTranslationY()) : 0;
569    }
570
571    public void setActionBarHideOffset(int offset) {
572        haltActionBarHideOffsetAnimations();
573        final int topHeight = mActionBarTop.getHeight();
574        offset = Math.max(0, Math.min(offset, topHeight));
575        mActionBarTop.setTranslationY(-offset);
576    }
577
578    void haltActionBarHideOffsetAnimations() {
579        removeCallbacks(mRemoveActionBarHideOffset);
580        removeCallbacks(mAddActionBarHideOffset);
581        if (mCurrentActionBarTopAnimator != null) {
582            mCurrentActionBarTopAnimator.cancel();
583        }
584    }
585
586    private void postRemoveActionBarHideOffset() {
587        haltActionBarHideOffsetAnimations();
588        postDelayed(mRemoveActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
589    }
590
591    private void postAddActionBarHideOffset() {
592        haltActionBarHideOffsetAnimations();
593        postDelayed(mAddActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
594    }
595
596    private void removeActionBarHideOffset() {
597        haltActionBarHideOffsetAnimations();
598        mRemoveActionBarHideOffset.run();
599    }
600
601    private void addActionBarHideOffset() {
602        haltActionBarHideOffsetAnimations();
603        mAddActionBarHideOffset.run();
604    }
605
606    private boolean shouldHideActionBarOnFling(float velocityX, float velocityY) {
607        mFlingEstimator.fling(0, 0, 0, (int) velocityY, 0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
608        final int finalY = mFlingEstimator.getFinalY();
609        return finalY > mActionBarTop.getHeight();
610    }
611
612    @Override
613    public void setWindowCallback(Window.Callback cb) {
614        pullChildren();
615        mDecorToolbar.setWindowCallback(cb);
616    }
617
618    @Override
619    public void setWindowTitle(CharSequence title) {
620        pullChildren();
621        mDecorToolbar.setWindowTitle(title);
622    }
623
624    @Override
625    public CharSequence getTitle() {
626        pullChildren();
627        return mDecorToolbar.getTitle();
628    }
629
630    @Override
631    public void initFeature(int windowFeature) {
632        pullChildren();
633        switch (windowFeature) {
634            case Window.FEATURE_PROGRESS:
635                mDecorToolbar.initProgress();
636                break;
637            case Window.FEATURE_INDETERMINATE_PROGRESS:
638                mDecorToolbar.initIndeterminateProgress();
639                break;
640            case AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR_OVERLAY:
641                setOverlayMode(true);
642                break;
643        }
644    }
645
646    @Override
647    public void setUiOptions(int uiOptions) {
648        // Split Action Bar not included.
649    }
650
651    @Override
652    public boolean hasIcon() {
653        pullChildren();
654        return mDecorToolbar.hasIcon();
655    }
656
657    @Override
658    public boolean hasLogo() {
659        pullChildren();
660        return mDecorToolbar.hasLogo();
661    }
662
663    @Override
664    public void setIcon(int resId) {
665        pullChildren();
666        mDecorToolbar.setIcon(resId);
667    }
668
669    @Override
670    public void setIcon(Drawable d) {
671        pullChildren();
672        mDecorToolbar.setIcon(d);
673    }
674
675    @Override
676    public void setLogo(int resId) {
677        pullChildren();
678        mDecorToolbar.setLogo(resId);
679    }
680
681    @Override
682    public boolean canShowOverflowMenu() {
683        pullChildren();
684        return mDecorToolbar.canShowOverflowMenu();
685    }
686
687    @Override
688    public boolean isOverflowMenuShowing() {
689        pullChildren();
690        return mDecorToolbar.isOverflowMenuShowing();
691    }
692
693    @Override
694    public boolean isOverflowMenuShowPending() {
695        pullChildren();
696        return mDecorToolbar.isOverflowMenuShowPending();
697    }
698
699    @Override
700    public boolean showOverflowMenu() {
701        pullChildren();
702        return mDecorToolbar.showOverflowMenu();
703    }
704
705    @Override
706    public boolean hideOverflowMenu() {
707        pullChildren();
708        return mDecorToolbar.hideOverflowMenu();
709    }
710
711    @Override
712    public void setMenuPrepared() {
713        pullChildren();
714        mDecorToolbar.setMenuPrepared();
715    }
716
717    @Override
718    public void setMenu(Menu menu, MenuPresenter.Callback cb) {
719        pullChildren();
720        mDecorToolbar.setMenu(menu, cb);
721    }
722
723    @Override
724    public void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
725        pullChildren();
726        mDecorToolbar.saveHierarchyState(toolbarStates);
727    }
728
729    @Override
730    public void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
731        pullChildren();
732        mDecorToolbar.restoreHierarchyState(toolbarStates);
733    }
734
735    @Override
736    public void dismissPopups() {
737        pullChildren();
738        mDecorToolbar.dismissPopupMenus();
739    }
740
741    public static class LayoutParams extends MarginLayoutParams {
742        public LayoutParams(Context c, AttributeSet attrs) {
743            super(c, attrs);
744        }
745
746        public LayoutParams(int width, int height) {
747            super(width, height);
748        }
749
750        public LayoutParams(ViewGroup.LayoutParams source) {
751            super(source);
752        }
753
754        public LayoutParams(ViewGroup.MarginLayoutParams source) {
755            super(source);
756        }
757    }
758
759    public interface ActionBarVisibilityCallback {
760        void onWindowVisibilityChanged(int visibility);
761        void showForSystem();
762        void hideForSystem();
763        void enableContentAnimations(boolean enable);
764        void onContentScrollStarted();
765        void onContentScrollStopped();
766    }
767}
768