• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.support.v7.widget;
18 
19 import android.content.Context;
20 import android.content.res.Configuration;
21 import android.content.res.TypedArray;
22 import android.graphics.Canvas;
23 import android.graphics.Rect;
24 import android.graphics.drawable.Drawable;
25 import android.os.Build;
26 import android.os.Parcelable;
27 import android.support.v4.view.NestedScrollingParent;
28 import android.support.v4.view.NestedScrollingParentHelper;
29 import android.support.v4.view.ViewCompat;
30 import android.support.v4.view.ViewPropertyAnimatorCompat;
31 import android.support.v4.view.ViewPropertyAnimatorListener;
32 import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
33 import android.support.v4.widget.ScrollerCompat;
34 import android.support.v7.app.AppCompatDelegate;
35 import android.support.v7.appcompat.R;
36 import android.support.v7.view.menu.MenuPresenter;
37 import android.util.AttributeSet;
38 import android.util.SparseArray;
39 import android.view.Menu;
40 import android.view.View;
41 import android.view.ViewGroup;
42 import 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  */
50 public 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 
ActionBarOverlayLayout(Context context)129     public ActionBarOverlayLayout(Context context) {
130         this(context, null);
131     }
132 
ActionBarOverlayLayout(Context context, AttributeSet attrs)133     public ActionBarOverlayLayout(Context context, AttributeSet attrs) {
134         super(context, attrs);
135         init(context);
136 
137         mParentHelper = new NestedScrollingParentHelper(this);
138     }
139 
init(Context context)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         super.onConfigurationChanged(newConfig);
216         init(getContext());
217         ViewCompat.requestApplyInsets(this);
218     }
219 
220     public void onWindowSystemUiVisibilityChanged(int visible) {
221         if (Build.VERSION.SDK_INT >= 16) {
222             super.onWindowSystemUiVisibilityChanged(visible);
223         }
224         pullChildren();
225         final int diff = mLastSystemUiVisibility ^ visible;
226         mLastSystemUiVisibility = visible;
227         final boolean barVisible = (visible & SYSTEM_UI_FLAG_FULLSCREEN) == 0;
228         final boolean stable = (visible & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
229         if (mActionBarVisibilityCallback != null) {
230             // We want the bar to be visible if it is not being hidden,
231             // or the app has not turned on a stable UI mode (meaning they
232             // are performing explicit layout around the action bar).
233             mActionBarVisibilityCallback.enableContentAnimations(!stable);
234             if (barVisible || !stable) mActionBarVisibilityCallback.showForSystem();
235             else mActionBarVisibilityCallback.hideForSystem();
236         }
237         if ((diff & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
238             if (mActionBarVisibilityCallback != null) {
239                 ViewCompat.requestApplyInsets(this);
240             }
241         }
242     }
243 
244     @Override
245     protected void onWindowVisibilityChanged(int visibility) {
246         super.onWindowVisibilityChanged(visibility);
247         mWindowVisibility = visibility;
248         if (mActionBarVisibilityCallback != null) {
249             mActionBarVisibilityCallback.onWindowVisibilityChanged(visibility);
250         }
251     }
252 
253     private boolean applyInsets(View view, Rect insets, boolean left, boolean top,
254             boolean bottom, boolean right) {
255         boolean changed = false;
256         LayoutParams lp = (LayoutParams)view.getLayoutParams();
257         if (left && lp.leftMargin != insets.left) {
258             changed = true;
259             lp.leftMargin = insets.left;
260         }
261         if (top && lp.topMargin != insets.top) {
262             changed = true;
263             lp.topMargin = insets.top;
264         }
265         if (right && lp.rightMargin != insets.right) {
266             changed = true;
267             lp.rightMargin = insets.right;
268         }
269         if (bottom && lp.bottomMargin != insets.bottom) {
270             changed = true;
271             lp.bottomMargin = insets.bottom;
272         }
273         return changed;
274     }
275 
276     @Override
277     protected boolean fitSystemWindows(Rect insets) {
278         pullChildren();
279 
280         final int vis = ViewCompat.getWindowSystemUiVisibility(this);
281         final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
282         final Rect systemInsets = insets;
283 
284         // The top action bar is always within the content area.
285         boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
286 
287         mBaseInnerInsets.set(systemInsets);
288         ViewUtils.computeFitSystemWindows(this, mBaseInnerInsets, mBaseContentInsets);
289         if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
290             changed = true;
291             mLastBaseContentInsets.set(mBaseContentInsets);
292         }
293 
294         if (changed) {
295             requestLayout();
296         }
297 
298         // We don't do any more at this point.  To correctly compute the content/inner
299         // insets in all cases, we need to know the measured size of the various action
300         // bar elements. fitSystemWindows() happens before the measure pass, so we can't
301         // do that here. Instead we will take this up in onMeasure().
302         return true;
303     }
304 
305     @Override
306     protected LayoutParams generateDefaultLayoutParams() {
307         return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
308     }
309 
310     @Override
311     public LayoutParams generateLayoutParams(AttributeSet attrs) {
312         return new LayoutParams(getContext(), attrs);
313     }
314 
315     @Override
316     protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
317         return new LayoutParams(p);
318     }
319 
320     @Override
321     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
322         return p instanceof LayoutParams;
323     }
324 
325     @Override
326     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
327         pullChildren();
328 
329         int maxHeight = 0;
330         int maxWidth = 0;
331         int childState = 0;
332 
333         int topInset = 0;
334         int bottomInset = 0;
335 
336         measureChildWithMargins(mActionBarTop, widthMeasureSpec, 0, heightMeasureSpec, 0);
337         LayoutParams lp = (LayoutParams) mActionBarTop.getLayoutParams();
338         maxWidth = Math.max(maxWidth,
339                 mActionBarTop.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
340         maxHeight = Math.max(maxHeight,
341                 mActionBarTop.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
342         childState = ViewUtils.combineMeasuredStates(childState,
343                 ViewCompat.getMeasuredState(mActionBarTop));
344 
345         final int vis = ViewCompat.getWindowSystemUiVisibility(this);
346         final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
347 
348         if (stable) {
349             // This is the standard space needed for the action bar.  For stable measurement,
350             // we can't depend on the size currently reported by it -- this must remain constant.
351             topInset = mActionBarHeight;
352             if (mHasNonEmbeddedTabs) {
353                 final View tabs = mActionBarTop.getTabContainer();
354                 if (tabs != null) {
355                     // If tabs are not embedded, increase space on top to account for them.
356                     topInset += mActionBarHeight;
357                 }
358             }
359         } else if (mActionBarTop.getVisibility() != GONE) {
360             // This is the space needed on top of the window for all of the action bar
361             // and tabs.
362             topInset = mActionBarTop.getMeasuredHeight();
363         }
364 
365         // If the window has not requested system UI layout flags, we need to
366         // make sure its content is not being covered by system UI...  though it
367         // will still be covered by the action bar if they have requested it to
368         // overlay.
369         mContentInsets.set(mBaseContentInsets);
370         mInnerInsets.set(mBaseInnerInsets);
371         if (!mOverlayMode && !stable) {
372             mContentInsets.top += topInset;
373             mContentInsets.bottom += bottomInset;
374         } else {
375             mInnerInsets.top += topInset;
376             mInnerInsets.bottom += bottomInset;
377         }
378         applyInsets(mContent, mContentInsets, true, true, true, true);
379 
380         if (!mLastInnerInsets.equals(mInnerInsets)) {
381             // If the inner insets have changed, we need to dispatch this down to
382             // the app's fitSystemWindows().  We do this before measuring the content
383             // view to keep the same semantics as the normal fitSystemWindows() call.
384             mLastInnerInsets.set(mInnerInsets);
385 
386             mContent.dispatchFitSystemWindows(mInnerInsets);
387         }
388 
389         measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);
390         lp = (LayoutParams) mContent.getLayoutParams();
391         maxWidth = Math.max(maxWidth,
392                 mContent.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
393         maxHeight = Math.max(maxHeight,
394                 mContent.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
395         childState = ViewUtils.combineMeasuredStates(childState,
396                 ViewCompat.getMeasuredState(mContent));
397 
398         // Account for padding too
399         maxWidth += getPaddingLeft() + getPaddingRight();
400         maxHeight += getPaddingTop() + getPaddingBottom();
401 
402         // Check against our minimum height and width
403         maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
404         maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
405 
406         setMeasuredDimension(
407                 ViewCompat.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
408                 ViewCompat.resolveSizeAndState(maxHeight, heightMeasureSpec,
409                         childState << MEASURED_HEIGHT_STATE_SHIFT));
410     }
411 
412     @Override
413     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
414         final int count = getChildCount();
415 
416         final int parentLeft = getPaddingLeft();
417         final int parentRight = right - left - getPaddingRight();
418 
419         final int parentTop = getPaddingTop();
420         final int parentBottom = bottom - top - getPaddingBottom();
421 
422         for (int i = 0; i < count; i++) {
423             final View child = getChildAt(i);
424             if (child.getVisibility() != GONE) {
425                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
426 
427                 final int width = child.getMeasuredWidth();
428                 final int height = child.getMeasuredHeight();
429 
430                 int childLeft = parentLeft + lp.leftMargin;
431                 int childTop = parentTop + lp.topMargin;
432 
433                 child.layout(childLeft, childTop, childLeft + width, childTop + height);
434             }
435         }
436     }
437 
438     @Override
439     public void draw(Canvas c) {
440         super.draw(c);
441         if (mWindowContentOverlay != null && !mIgnoreWindowContentOverlay) {
442             final int top = mActionBarTop.getVisibility() == VISIBLE ?
443                     (int) (mActionBarTop.getBottom() + ViewCompat.getTranslationY(mActionBarTop) + 0.5f)
444                     : 0;
445             mWindowContentOverlay.setBounds(0, top, getWidth(),
446                     top + mWindowContentOverlay.getIntrinsicHeight());
447             mWindowContentOverlay.draw(c);
448         }
449     }
450 
451     @Override
452     public boolean shouldDelayChildPressedState() {
453         return false;
454     }
455 
456     @Override
457     public boolean onStartNestedScroll(View child, View target, int axes) {
458         if ((axes & SCROLL_AXIS_VERTICAL) == 0 || mActionBarTop.getVisibility() != VISIBLE) {
459             return false;
460         }
461         return mHideOnContentScroll;
462     }
463 
464     @Override
465     public void onNestedScrollAccepted(View child, View target, int axes) {
466         mParentHelper.onNestedScrollAccepted(child, target, axes);
467         mHideOnContentScrollReference = getActionBarHideOffset();
468         haltActionBarHideOffsetAnimations();
469         if (mActionBarVisibilityCallback != null) {
470             mActionBarVisibilityCallback.onContentScrollStarted();
471         }
472     }
473 
474     @Override
475     public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
476             int dxUnconsumed, int dyUnconsumed) {
477         mHideOnContentScrollReference += dyConsumed;
478         setActionBarHideOffset(mHideOnContentScrollReference);
479     }
480 
481     @Override
482     public void onStopNestedScroll(View target) {
483         if (mHideOnContentScroll && !mAnimatingForFling) {
484             if (mHideOnContentScrollReference <= mActionBarTop.getHeight()) {
485                 postRemoveActionBarHideOffset();
486             } else {
487                 postAddActionBarHideOffset();
488             }
489         }
490         if (mActionBarVisibilityCallback != null) {
491             mActionBarVisibilityCallback.onContentScrollStopped();
492         }
493     }
494 
495     @Override
496     public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
497         if (!mHideOnContentScroll || !consumed) {
498             return false;
499         }
500         if (shouldHideActionBarOnFling(velocityX, velocityY)) {
501             addActionBarHideOffset();
502         } else {
503             removeActionBarHideOffset();
504         }
505         mAnimatingForFling = true;
506         return true;
507     }
508 
509     @Override
510     public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
511         // no-op
512     }
513 
514     @Override
515     public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
516         return false;
517     }
518 
519     @Override
520     public int getNestedScrollAxes() {
521         return mParentHelper.getNestedScrollAxes();
522     }
523 
524     void pullChildren() {
525         if (mContent == null) {
526             mContent = (ContentFrameLayout) findViewById(R.id.action_bar_activity_content);
527             mActionBarTop = (ActionBarContainer) findViewById(R.id.action_bar_container);
528             mDecorToolbar = getDecorToolbar(findViewById(R.id.action_bar));
529         }
530     }
531 
532     private DecorToolbar getDecorToolbar(View view) {
533         if (view instanceof DecorToolbar) {
534             return (DecorToolbar) view;
535         } else if (view instanceof Toolbar) {
536             return ((Toolbar) view).getWrapper();
537         } else {
538             throw new IllegalStateException("Can't make a decor toolbar out of " +
539                     view.getClass().getSimpleName());
540         }
541     }
542 
543     public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
544         if (hideOnContentScroll != mHideOnContentScroll) {
545             mHideOnContentScroll = hideOnContentScroll;
546             if (!hideOnContentScroll) {
547                 haltActionBarHideOffsetAnimations();
548                 setActionBarHideOffset(0);
549             }
550         }
551     }
552 
553     public boolean isHideOnContentScrollEnabled() {
554         return mHideOnContentScroll;
555     }
556 
557     public int getActionBarHideOffset() {
558         return mActionBarTop != null ? -((int) ViewCompat.getTranslationY(mActionBarTop)) : 0;
559     }
560 
561     public void setActionBarHideOffset(int offset) {
562         haltActionBarHideOffsetAnimations();
563         final int topHeight = mActionBarTop.getHeight();
564         offset = Math.max(0, Math.min(offset, topHeight));
565         ViewCompat.setTranslationY(mActionBarTop, -offset);
566     }
567 
568     private void haltActionBarHideOffsetAnimations() {
569         removeCallbacks(mRemoveActionBarHideOffset);
570         removeCallbacks(mAddActionBarHideOffset);
571         if (mCurrentActionBarTopAnimator != null) {
572             mCurrentActionBarTopAnimator.cancel();
573         }
574     }
575 
576     private void postRemoveActionBarHideOffset() {
577         haltActionBarHideOffsetAnimations();
578         postDelayed(mRemoveActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
579     }
580 
581     private void postAddActionBarHideOffset() {
582         haltActionBarHideOffsetAnimations();
583         postDelayed(mAddActionBarHideOffset, ACTION_BAR_ANIMATE_DELAY);
584     }
585 
586     private void removeActionBarHideOffset() {
587         haltActionBarHideOffsetAnimations();
588         mRemoveActionBarHideOffset.run();
589     }
590 
591     private void addActionBarHideOffset() {
592         haltActionBarHideOffsetAnimations();
593         mAddActionBarHideOffset.run();
594     }
595 
596     private boolean shouldHideActionBarOnFling(float velocityX, float velocityY) {
597         mFlingEstimator.fling(0, 0, 0, (int) velocityY, 0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
598         final int finalY = mFlingEstimator.getFinalY();
599         return finalY > mActionBarTop.getHeight();
600     }
601 
602     @Override
603     public void setWindowCallback(Window.Callback cb) {
604         pullChildren();
605         mDecorToolbar.setWindowCallback(cb);
606     }
607 
608     @Override
609     public void setWindowTitle(CharSequence title) {
610         pullChildren();
611         mDecorToolbar.setWindowTitle(title);
612     }
613 
614     @Override
615     public CharSequence getTitle() {
616         pullChildren();
617         return mDecorToolbar.getTitle();
618     }
619 
620     @Override
621     public void initFeature(int windowFeature) {
622         pullChildren();
623         switch (windowFeature) {
624             case Window.FEATURE_PROGRESS:
625                 mDecorToolbar.initProgress();
626                 break;
627             case Window.FEATURE_INDETERMINATE_PROGRESS:
628                 mDecorToolbar.initIndeterminateProgress();
629                 break;
630             case AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR_OVERLAY:
631                 setOverlayMode(true);
632                 break;
633         }
634     }
635 
636     @Override
637     public void setUiOptions(int uiOptions) {
638         // Split Action Bar not included.
639     }
640 
641     @Override
642     public boolean hasIcon() {
643         pullChildren();
644         return mDecorToolbar.hasIcon();
645     }
646 
647     @Override
648     public boolean hasLogo() {
649         pullChildren();
650         return mDecorToolbar.hasLogo();
651     }
652 
653     @Override
654     public void setIcon(int resId) {
655         pullChildren();
656         mDecorToolbar.setIcon(resId);
657     }
658 
659     @Override
660     public void setIcon(Drawable d) {
661         pullChildren();
662         mDecorToolbar.setIcon(d);
663     }
664 
665     @Override
666     public void setLogo(int resId) {
667         pullChildren();
668         mDecorToolbar.setLogo(resId);
669     }
670 
671     @Override
672     public boolean canShowOverflowMenu() {
673         pullChildren();
674         return mDecorToolbar.canShowOverflowMenu();
675     }
676 
677     @Override
678     public boolean isOverflowMenuShowing() {
679         pullChildren();
680         return mDecorToolbar.isOverflowMenuShowing();
681     }
682 
683     @Override
684     public boolean isOverflowMenuShowPending() {
685         pullChildren();
686         return mDecorToolbar.isOverflowMenuShowPending();
687     }
688 
689     @Override
690     public boolean showOverflowMenu() {
691         pullChildren();
692         return mDecorToolbar.showOverflowMenu();
693     }
694 
695     @Override
696     public boolean hideOverflowMenu() {
697         pullChildren();
698         return mDecorToolbar.hideOverflowMenu();
699     }
700 
701     @Override
702     public void setMenuPrepared() {
703         pullChildren();
704         mDecorToolbar.setMenuPrepared();
705     }
706 
707     @Override
708     public void setMenu(Menu menu, MenuPresenter.Callback cb) {
709         pullChildren();
710         mDecorToolbar.setMenu(menu, cb);
711     }
712 
713     @Override
714     public void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
715         pullChildren();
716         mDecorToolbar.saveHierarchyState(toolbarStates);
717     }
718 
719     @Override
720     public void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
721         pullChildren();
722         mDecorToolbar.restoreHierarchyState(toolbarStates);
723     }
724 
725     @Override
726     public void dismissPopups() {
727         pullChildren();
728         mDecorToolbar.dismissPopupMenus();
729     }
730 
731     public static class LayoutParams extends MarginLayoutParams {
732         public LayoutParams(Context c, AttributeSet attrs) {
733             super(c, attrs);
734         }
735 
736         public LayoutParams(int width, int height) {
737             super(width, height);
738         }
739 
740         public LayoutParams(ViewGroup.LayoutParams source) {
741             super(source);
742         }
743 
744         public LayoutParams(ViewGroup.MarginLayoutParams source) {
745             super(source);
746         }
747     }
748 
749     public interface ActionBarVisibilityCallback {
750         void onWindowVisibilityChanged(int visibility);
751         void showForSystem();
752         void hideForSystem();
753         void enableContentAnimations(boolean enable);
754         void onContentScrollStarted();
755         void onContentScrollStopped();
756     }
757 }
758