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