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