[go: nahoru, domu]

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