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