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