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