1 /* 2 * Copyright (C) 2014 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.internal.app; 18 19 import android.app.Dialog; 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.content.res.Resources; 23 import android.content.res.TypedArray; 24 import android.graphics.drawable.Drawable; 25 import android.os.Build; 26 import android.support.v4.app.FragmentActivity; 27 import android.support.v4.app.FragmentTransaction; 28 import android.support.v4.view.ViewCompat; 29 import android.support.v4.view.ViewPropertyAnimatorCompat; 30 import android.support.v4.view.ViewPropertyAnimatorListener; 31 import android.support.v4.view.ViewPropertyAnimatorListenerAdapter; 32 import android.support.v4.view.ViewPropertyAnimatorUpdateListener; 33 import android.support.v7.app.ActionBar; 34 import android.support.v7.app.ActionBarActivity; 35 import android.support.v7.appcompat.R; 36 import android.support.v7.internal.view.ActionBarPolicy; 37 import android.support.v7.internal.view.ViewPropertyAnimatorCompatSet; 38 import android.support.v7.internal.view.SupportMenuInflater; 39 import android.support.v7.internal.view.menu.MenuBuilder; 40 import android.support.v7.internal.view.menu.MenuPopupHelper; 41 import android.support.v7.internal.view.menu.SubMenuBuilder; 42 import android.support.v7.internal.widget.ActionBarContainer; 43 import android.support.v7.internal.widget.ActionBarContextView; 44 import android.support.v7.internal.widget.ActionBarOverlayLayout; 45 import android.support.v7.internal.widget.DecorToolbar; 46 import android.support.v7.internal.widget.TintManager; 47 import android.support.v7.internal.widget.ScrollingTabContainerView; 48 import android.support.v7.view.ActionMode; 49 import android.support.v7.widget.Toolbar; 50 import android.util.TypedValue; 51 import android.view.ContextThemeWrapper; 52 import android.view.LayoutInflater; 53 import android.view.Menu; 54 import android.view.MenuInflater; 55 import android.view.MenuItem; 56 import android.view.View; 57 import android.view.ViewParent; 58 import android.view.Window; 59 import android.view.accessibility.AccessibilityEvent; 60 import android.view.animation.AnimationUtils; 61 import android.widget.SpinnerAdapter; 62 63 import java.lang.ref.WeakReference; 64 import java.util.ArrayList; 65 66 /** 67 * WindowDecorActionBar is the ActionBar implementation used 68 * by devices of all screen sizes as part of the window decor layout. 69 * If it detects a compatible decor, it will split contextual modes 70 * across both the ActionBarView at the top of the screen and 71 * a horizontal LinearLayout at the bottom which is normally hidden. 72 * 73 * @hide 74 */ 75 public class WindowDecorActionBar extends ActionBar implements 76 ActionBarOverlayLayout.ActionBarVisibilityCallback { 77 private static final String TAG = "WindowDecorActionBar"; 78 79 /** 80 * Only allow show/hide animations on ICS+, as that is what ViewPropertyAnimatorCompat supports 81 */ 82 private static final boolean ALLOW_SHOW_HIDE_ANIMATIONS = Build.VERSION.SDK_INT >= 14; 83 84 private Context mContext; 85 private Context mThemedContext; 86 private FragmentActivity mActivity; 87 private Dialog mDialog; 88 89 private ActionBarOverlayLayout mOverlayLayout; 90 private ActionBarContainer mContainerView; 91 private DecorToolbar mDecorToolbar; 92 private ActionBarContextView mContextView; 93 private ActionBarContainer mSplitView; 94 private View mContentView; 95 private ScrollingTabContainerView mTabScrollView; 96 97 private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>(); 98 99 private TabImpl mSelectedTab; 100 private int mSavedTabPosition = INVALID_POSITION; 101 102 private boolean mDisplayHomeAsUpSet; 103 104 ActionModeImpl mActionMode; 105 ActionMode mDeferredDestroyActionMode; 106 ActionMode.Callback mDeferredModeDestroyCallback; 107 108 private boolean mLastMenuVisibility; 109 private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners = 110 new ArrayList<OnMenuVisibilityListener>(); 111 112 private static final int CONTEXT_DISPLAY_NORMAL = 0; 113 private static final int CONTEXT_DISPLAY_SPLIT = 1; 114 115 private static final int INVALID_POSITION = -1; 116 117 private int mContextDisplayMode; 118 private boolean mHasEmbeddedTabs; 119 120 private int mCurWindowVisibility = View.VISIBLE; 121 122 private boolean mContentAnimations = true; 123 private boolean mHiddenByApp; 124 private boolean mHiddenBySystem; 125 private boolean mShowingForMode; 126 127 private boolean mNowShowing = true; 128 129 private ViewPropertyAnimatorCompatSet mCurrentShowAnim; 130 private boolean mShowHideAnimationEnabled; 131 boolean mHideOnContentScroll; 132 133 private TintManager mTintManager; 134 135 final ViewPropertyAnimatorListener mHideListener = new ViewPropertyAnimatorListenerAdapter() { 136 @Override 137 public void onAnimationEnd(View view) { 138 if (mContentAnimations && mContentView != null) { 139 ViewCompat.setTranslationY(mContentView, 0f); 140 ViewCompat.setTranslationY(mContainerView, 0f); 141 } 142 if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { 143 mSplitView.setVisibility(View.GONE); 144 } 145 mContainerView.setVisibility(View.GONE); 146 mContainerView.setTransitioning(false); 147 mCurrentShowAnim = null; 148 completeDeferredDestroyActionMode(); 149 if (mOverlayLayout != null) { 150 ViewCompat.requestApplyInsets(mOverlayLayout); 151 } 152 } 153 }; 154 155 final ViewPropertyAnimatorListener mShowListener = new ViewPropertyAnimatorListenerAdapter() { 156 @Override 157 public void onAnimationEnd(View view) { 158 mCurrentShowAnim = null; 159 mContainerView.requestLayout(); 160 } 161 }; 162 163 final ViewPropertyAnimatorUpdateListener mUpdateListener = 164 new ViewPropertyAnimatorUpdateListener() { 165 @Override 166 public void onAnimationUpdate(View view) { 167 final ViewParent parent = mContainerView.getParent(); 168 ((View) parent).invalidate(); 169 } 170 }; 171 WindowDecorActionBar(ActionBarActivity activity, boolean overlayMode)172 public WindowDecorActionBar(ActionBarActivity activity, boolean overlayMode) { 173 mActivity = activity; 174 Window window = activity.getWindow(); 175 View decor = window.getDecorView(); 176 init(decor); 177 if (!overlayMode) { 178 mContentView = decor.findViewById(android.R.id.content); 179 } 180 } 181 WindowDecorActionBar(Dialog dialog)182 public WindowDecorActionBar(Dialog dialog) { 183 mDialog = dialog; 184 init(dialog.getWindow().getDecorView()); 185 } 186 187 /** 188 * Only for edit mode. 189 * @hide 190 */ WindowDecorActionBar(View layout)191 public WindowDecorActionBar(View layout) { 192 assert layout.isInEditMode(); 193 init(layout); 194 } 195 init(View decor)196 private void init(View decor) { 197 mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(R.id.decor_content_parent); 198 if (mOverlayLayout != null) { 199 mOverlayLayout.setActionBarVisibilityCallback(this); 200 } 201 mDecorToolbar = getDecorToolbar(decor.findViewById(R.id.action_bar)); 202 mContextView = (ActionBarContextView) decor.findViewById( 203 R.id.action_context_bar); 204 mContainerView = (ActionBarContainer) decor.findViewById( 205 R.id.action_bar_container); 206 207 mSplitView = (ActionBarContainer) decor.findViewById(R.id.split_action_bar); 208 209 if (mDecorToolbar == null || mContextView == null || mContainerView == null) { 210 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 211 "with a compatible window decor layout"); 212 } 213 214 mContext = mDecorToolbar.getContext(); 215 mContextDisplayMode = mDecorToolbar.isSplit() ? 216 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; 217 218 // This was initially read from the action bar style 219 final int current = mDecorToolbar.getDisplayOptions(); 220 final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0; 221 if (homeAsUp) { 222 mDisplayHomeAsUpSet = true; 223 } 224 225 ActionBarPolicy abp = ActionBarPolicy.get(mContext); 226 setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp); 227 setHasEmbeddedTabs(abp.hasEmbeddedTabs()); 228 229 final TypedArray a = mContext.obtainStyledAttributes(null, 230 R.styleable.ActionBar, 231 R.attr.actionBarStyle, 0); 232 if (a.getBoolean(R.styleable.ActionBar_hideOnContentScroll, false)) { 233 setHideOnContentScrollEnabled(true); 234 } 235 final int elevation = a.getDimensionPixelSize(R.styleable.ActionBar_elevation, 0); 236 if (elevation != 0) { 237 setElevation(elevation); 238 } 239 a.recycle(); 240 } 241 getDecorToolbar(View view)242 private DecorToolbar getDecorToolbar(View view) { 243 if (view instanceof DecorToolbar) { 244 return (DecorToolbar) view; 245 } else if (view instanceof Toolbar) { 246 return ((Toolbar) view).getWrapper(); 247 } else { 248 throw new IllegalStateException("Can't make a decor toolbar out of " + 249 view.getClass().getSimpleName()); 250 } 251 } 252 253 @Override setElevation(float elevation)254 public void setElevation(float elevation) { 255 ViewCompat.setElevation(mContainerView, elevation); 256 if (mSplitView != null) { 257 ViewCompat.setElevation(mSplitView, elevation); 258 } 259 } 260 261 @Override getElevation()262 public float getElevation() { 263 return ViewCompat.getElevation(mContainerView); 264 } 265 onConfigurationChanged(Configuration newConfig)266 public void onConfigurationChanged(Configuration newConfig) { 267 setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs()); 268 } 269 setHasEmbeddedTabs(boolean hasEmbeddedTabs)270 private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) { 271 mHasEmbeddedTabs = hasEmbeddedTabs; 272 // Switch tab layout configuration if needed 273 if (!mHasEmbeddedTabs) { 274 mDecorToolbar.setEmbeddedTabView(null); 275 mContainerView.setTabContainer(mTabScrollView); 276 } else { 277 mContainerView.setTabContainer(null); 278 mDecorToolbar.setEmbeddedTabView(mTabScrollView); 279 } 280 final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS; 281 if (mTabScrollView != null) { 282 if (isInTabMode) { 283 mTabScrollView.setVisibility(View.VISIBLE); 284 if (mOverlayLayout != null) { 285 ViewCompat.requestApplyInsets(mOverlayLayout); 286 } 287 } else { 288 mTabScrollView.setVisibility(View.GONE); 289 } 290 } 291 mDecorToolbar.setCollapsible(!mHasEmbeddedTabs && isInTabMode); 292 mOverlayLayout.setHasNonEmbeddedTabs(!mHasEmbeddedTabs && isInTabMode); 293 } 294 ensureTabsExist()295 private void ensureTabsExist() { 296 if (mTabScrollView != null) { 297 return; 298 } 299 300 ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext); 301 302 if (mHasEmbeddedTabs) { 303 tabScroller.setVisibility(View.VISIBLE); 304 mDecorToolbar.setEmbeddedTabView(tabScroller); 305 } else { 306 if (getNavigationMode() == NAVIGATION_MODE_TABS) { 307 tabScroller.setVisibility(View.VISIBLE); 308 if (mOverlayLayout != null) { 309 ViewCompat.requestApplyInsets(mOverlayLayout); 310 } 311 } else { 312 tabScroller.setVisibility(View.GONE); 313 } 314 mContainerView.setTabContainer(tabScroller); 315 } 316 mTabScrollView = tabScroller; 317 } 318 completeDeferredDestroyActionMode()319 void completeDeferredDestroyActionMode() { 320 if (mDeferredModeDestroyCallback != null) { 321 mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode); 322 mDeferredDestroyActionMode = null; 323 mDeferredModeDestroyCallback = null; 324 } 325 } 326 onWindowVisibilityChanged(int visibility)327 public void onWindowVisibilityChanged(int visibility) { 328 mCurWindowVisibility = visibility; 329 } 330 331 /** 332 * Enables or disables animation between show/hide states. 333 * If animation is disabled using this method, animations in progress 334 * will be finished. 335 * 336 * @param enabled true to animate, false to not animate. 337 */ setShowHideAnimationEnabled(boolean enabled)338 public void setShowHideAnimationEnabled(boolean enabled) { 339 mShowHideAnimationEnabled = enabled; 340 if (!enabled && mCurrentShowAnim != null) { 341 mCurrentShowAnim.cancel(); 342 } 343 } 344 addOnMenuVisibilityListener(OnMenuVisibilityListener listener)345 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { 346 mMenuVisibilityListeners.add(listener); 347 } 348 removeOnMenuVisibilityListener(OnMenuVisibilityListener listener)349 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) { 350 mMenuVisibilityListeners.remove(listener); 351 } 352 dispatchMenuVisibilityChanged(boolean isVisible)353 public void dispatchMenuVisibilityChanged(boolean isVisible) { 354 if (isVisible == mLastMenuVisibility) { 355 return; 356 } 357 mLastMenuVisibility = isVisible; 358 359 final int count = mMenuVisibilityListeners.size(); 360 for (int i = 0; i < count; i++) { 361 mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible); 362 } 363 } 364 365 @Override setCustomView(int resId)366 public void setCustomView(int resId) { 367 setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId, 368 mDecorToolbar.getViewGroup(), false)); 369 } 370 371 @Override setDisplayUseLogoEnabled(boolean useLogo)372 public void setDisplayUseLogoEnabled(boolean useLogo) { 373 setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO); 374 } 375 376 @Override setDisplayShowHomeEnabled(boolean showHome)377 public void setDisplayShowHomeEnabled(boolean showHome) { 378 setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME); 379 } 380 381 @Override setDisplayHomeAsUpEnabled(boolean showHomeAsUp)382 public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { 383 setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP); 384 } 385 386 @Override setDisplayShowTitleEnabled(boolean showTitle)387 public void setDisplayShowTitleEnabled(boolean showTitle) { 388 setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE); 389 } 390 391 @Override setDisplayShowCustomEnabled(boolean showCustom)392 public void setDisplayShowCustomEnabled(boolean showCustom) { 393 setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM); 394 } 395 396 @Override setHomeButtonEnabled(boolean enable)397 public void setHomeButtonEnabled(boolean enable) { 398 mDecorToolbar.setHomeButtonEnabled(enable); 399 } 400 401 @Override setTitle(int resId)402 public void setTitle(int resId) { 403 setTitle(mContext.getString(resId)); 404 } 405 406 @Override setSubtitle(int resId)407 public void setSubtitle(int resId) { 408 setSubtitle(mContext.getString(resId)); 409 } 410 setSelectedNavigationItem(int position)411 public void setSelectedNavigationItem(int position) { 412 switch (mDecorToolbar.getNavigationMode()) { 413 case NAVIGATION_MODE_TABS: 414 selectTab(mTabs.get(position)); 415 break; 416 case NAVIGATION_MODE_LIST: 417 mDecorToolbar.setDropdownSelectedPosition(position); 418 break; 419 default: 420 throw new IllegalStateException( 421 "setSelectedNavigationIndex not valid for current navigation mode"); 422 } 423 } 424 removeAllTabs()425 public void removeAllTabs() { 426 cleanupTabs(); 427 } 428 cleanupTabs()429 private void cleanupTabs() { 430 if (mSelectedTab != null) { 431 selectTab(null); 432 } 433 mTabs.clear(); 434 if (mTabScrollView != null) { 435 mTabScrollView.removeAllTabs(); 436 } 437 mSavedTabPosition = INVALID_POSITION; 438 } 439 setTitle(CharSequence title)440 public void setTitle(CharSequence title) { 441 mDecorToolbar.setTitle(title); 442 } 443 444 @Override setWindowTitle(CharSequence title)445 public void setWindowTitle(CharSequence title) { 446 mDecorToolbar.setWindowTitle(title); 447 } 448 setSubtitle(CharSequence subtitle)449 public void setSubtitle(CharSequence subtitle) { 450 mDecorToolbar.setSubtitle(subtitle); 451 } 452 setDisplayOptions(int options)453 public void setDisplayOptions(int options) { 454 if ((options & DISPLAY_HOME_AS_UP) != 0) { 455 mDisplayHomeAsUpSet = true; 456 } 457 mDecorToolbar.setDisplayOptions(options); 458 } 459 setDisplayOptions(int options, int mask)460 public void setDisplayOptions(int options, int mask) { 461 final int current = mDecorToolbar.getDisplayOptions(); 462 if ((mask & DISPLAY_HOME_AS_UP) != 0) { 463 mDisplayHomeAsUpSet = true; 464 } 465 mDecorToolbar.setDisplayOptions((options & mask) | (current & ~mask)); 466 } 467 setBackgroundDrawable(Drawable d)468 public void setBackgroundDrawable(Drawable d) { 469 mContainerView.setPrimaryBackground(d); 470 } 471 setStackedBackgroundDrawable(Drawable d)472 public void setStackedBackgroundDrawable(Drawable d) { 473 mContainerView.setStackedBackground(d); 474 } 475 setSplitBackgroundDrawable(Drawable d)476 public void setSplitBackgroundDrawable(Drawable d) { 477 if (mSplitView != null) { 478 mSplitView.setSplitBackground(d); 479 } 480 } 481 getCustomView()482 public View getCustomView() { 483 return mDecorToolbar.getCustomView(); 484 } 485 getTitle()486 public CharSequence getTitle() { 487 return mDecorToolbar.getTitle(); 488 } 489 getSubtitle()490 public CharSequence getSubtitle() { 491 return mDecorToolbar.getSubtitle(); 492 } 493 getNavigationMode()494 public int getNavigationMode() { 495 return mDecorToolbar.getNavigationMode(); 496 } 497 getDisplayOptions()498 public int getDisplayOptions() { 499 return mDecorToolbar.getDisplayOptions(); 500 } 501 startActionMode(ActionMode.Callback callback)502 public ActionMode startActionMode(ActionMode.Callback callback) { 503 if (mActionMode != null) { 504 mActionMode.finish(); 505 } 506 507 mOverlayLayout.setHideOnContentScrollEnabled(false); 508 mContextView.killMode(); 509 ActionModeImpl mode = new ActionModeImpl(mContextView.getContext(), callback); 510 if (mode.dispatchOnCreate()) { 511 mode.invalidate(); 512 mContextView.initForMode(mode); 513 animateToMode(true); 514 if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { 515 // TODO animate this 516 if (mSplitView.getVisibility() != View.VISIBLE) { 517 mSplitView.setVisibility(View.VISIBLE); 518 if (mOverlayLayout != null) { 519 ViewCompat.requestApplyInsets(mOverlayLayout); 520 } 521 } 522 } 523 mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 524 mActionMode = mode; 525 return mode; 526 } 527 return null; 528 } 529 configureTab(Tab tab, int position)530 private void configureTab(Tab tab, int position) { 531 final TabImpl tabi = (TabImpl) tab; 532 final ActionBar.TabListener callback = tabi.getCallback(); 533 534 if (callback == null) { 535 throw new IllegalStateException("Action Bar Tab must have a Callback"); 536 } 537 538 tabi.setPosition(position); 539 mTabs.add(position, tabi); 540 541 final int count = mTabs.size(); 542 for (int i = position + 1; i < count; i++) { 543 mTabs.get(i).setPosition(i); 544 } 545 } 546 547 @Override addTab(Tab tab)548 public void addTab(Tab tab) { 549 addTab(tab, mTabs.isEmpty()); 550 } 551 552 @Override addTab(Tab tab, int position)553 public void addTab(Tab tab, int position) { 554 addTab(tab, position, mTabs.isEmpty()); 555 } 556 557 @Override addTab(Tab tab, boolean setSelected)558 public void addTab(Tab tab, boolean setSelected) { 559 ensureTabsExist(); 560 mTabScrollView.addTab(tab, setSelected); 561 configureTab(tab, mTabs.size()); 562 if (setSelected) { 563 selectTab(tab); 564 } 565 } 566 567 @Override addTab(Tab tab, int position, boolean setSelected)568 public void addTab(Tab tab, int position, boolean setSelected) { 569 ensureTabsExist(); 570 mTabScrollView.addTab(tab, position, setSelected); 571 configureTab(tab, position); 572 if (setSelected) { 573 selectTab(tab); 574 } 575 } 576 577 @Override newTab()578 public Tab newTab() { 579 return new TabImpl(); 580 } 581 582 @Override removeTab(Tab tab)583 public void removeTab(Tab tab) { 584 removeTabAt(tab.getPosition()); 585 } 586 587 @Override removeTabAt(int position)588 public void removeTabAt(int position) { 589 if (mTabScrollView == null) { 590 // No tabs around to remove 591 return; 592 } 593 594 int selectedTabPosition = mSelectedTab != null 595 ? mSelectedTab.getPosition() : mSavedTabPosition; 596 mTabScrollView.removeTabAt(position); 597 TabImpl removedTab = mTabs.remove(position); 598 if (removedTab != null) { 599 removedTab.setPosition(-1); 600 } 601 602 final int newTabCount = mTabs.size(); 603 for (int i = position; i < newTabCount; i++) { 604 mTabs.get(i).setPosition(i); 605 } 606 607 if (selectedTabPosition == position) { 608 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1))); 609 } 610 } 611 612 @Override selectTab(Tab tab)613 public void selectTab(Tab tab) { 614 if (getNavigationMode() != NAVIGATION_MODE_TABS) { 615 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION; 616 return; 617 } 618 619 final FragmentTransaction trans = mDecorToolbar.getViewGroup().isInEditMode() ? null : 620 mActivity.getSupportFragmentManager().beginTransaction().disallowAddToBackStack(); 621 622 if (mSelectedTab == tab) { 623 if (mSelectedTab != null) { 624 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans); 625 mTabScrollView.animateToTab(tab.getPosition()); 626 } 627 } else { 628 mTabScrollView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION); 629 if (mSelectedTab != null) { 630 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans); 631 } 632 mSelectedTab = (TabImpl) tab; 633 if (mSelectedTab != null) { 634 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans); 635 } 636 } 637 638 if (trans != null && !trans.isEmpty()) { 639 trans.commit(); 640 } 641 } 642 643 @Override getSelectedTab()644 public Tab getSelectedTab() { 645 return mSelectedTab; 646 } 647 648 @Override getHeight()649 public int getHeight() { 650 return mContainerView.getHeight(); 651 } 652 enableContentAnimations(boolean enabled)653 public void enableContentAnimations(boolean enabled) { 654 mContentAnimations = enabled; 655 } 656 657 @Override show()658 public void show() { 659 if (mHiddenByApp) { 660 mHiddenByApp = false; 661 updateVisibility(false); 662 } 663 } 664 showForActionMode()665 private void showForActionMode() { 666 if (!mShowingForMode) { 667 mShowingForMode = true; 668 if (mOverlayLayout != null) { 669 mOverlayLayout.setShowingForActionMode(true); 670 } 671 updateVisibility(false); 672 } 673 } 674 showForSystem()675 public void showForSystem() { 676 if (mHiddenBySystem) { 677 mHiddenBySystem = false; 678 updateVisibility(true); 679 } 680 } 681 682 @Override hide()683 public void hide() { 684 if (!mHiddenByApp) { 685 mHiddenByApp = true; 686 updateVisibility(false); 687 } 688 } 689 hideForActionMode()690 private void hideForActionMode() { 691 if (mShowingForMode) { 692 mShowingForMode = false; 693 if (mOverlayLayout != null) { 694 mOverlayLayout.setShowingForActionMode(false); 695 } 696 updateVisibility(false); 697 } 698 } 699 hideForSystem()700 public void hideForSystem() { 701 if (!mHiddenBySystem) { 702 mHiddenBySystem = true; 703 updateVisibility(true); 704 } 705 } 706 707 @Override setHideOnContentScrollEnabled(boolean hideOnContentScroll)708 public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) { 709 if (hideOnContentScroll && !mOverlayLayout.isInOverlayMode()) { 710 throw new IllegalStateException("Action bar must be in overlay mode " + 711 "(Window.FEATURE_OVERLAY_ACTION_BAR) to enable hide on content scroll"); 712 } 713 mHideOnContentScroll = hideOnContentScroll; 714 mOverlayLayout.setHideOnContentScrollEnabled(hideOnContentScroll); 715 } 716 717 @Override isHideOnContentScrollEnabled()718 public boolean isHideOnContentScrollEnabled() { 719 return mOverlayLayout.isHideOnContentScrollEnabled(); 720 } 721 722 @Override getHideOffset()723 public int getHideOffset() { 724 return mOverlayLayout.getActionBarHideOffset(); 725 } 726 727 @Override setHideOffset(int offset)728 public void setHideOffset(int offset) { 729 if (offset != 0 && !mOverlayLayout.isInOverlayMode()) { 730 throw new IllegalStateException("Action bar must be in overlay mode " + 731 "(Window.FEATURE_OVERLAY_ACTION_BAR) to set a non-zero hide offset"); 732 } 733 mOverlayLayout.setActionBarHideOffset(offset); 734 } 735 checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem, boolean showingForMode)736 private static boolean checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem, 737 boolean showingForMode) { 738 if (showingForMode) { 739 return true; 740 } else if (hiddenByApp || hiddenBySystem) { 741 return false; 742 } else { 743 return true; 744 } 745 } 746 updateVisibility(boolean fromSystem)747 private void updateVisibility(boolean fromSystem) { 748 // Based on the current state, should we be hidden or shown? 749 final boolean shown = checkShowingFlags(mHiddenByApp, mHiddenBySystem, 750 mShowingForMode); 751 752 if (shown) { 753 if (!mNowShowing) { 754 mNowShowing = true; 755 doShow(fromSystem); 756 } 757 } else { 758 if (mNowShowing) { 759 mNowShowing = false; 760 doHide(fromSystem); 761 } 762 } 763 } 764 doShow(boolean fromSystem)765 public void doShow(boolean fromSystem) { 766 if (mCurrentShowAnim != null) { 767 mCurrentShowAnim.cancel(); 768 } 769 mContainerView.setVisibility(View.VISIBLE); 770 771 if (mCurWindowVisibility == View.VISIBLE && ALLOW_SHOW_HIDE_ANIMATIONS && 772 (mShowHideAnimationEnabled || fromSystem)) { 773 // because we're about to ask its window loc 774 ViewCompat.setTranslationY(mContainerView, 0f); 775 float startingY = -mContainerView.getHeight(); 776 if (fromSystem) { 777 int topLeft[] = {0, 0}; 778 mContainerView.getLocationInWindow(topLeft); 779 startingY -= topLeft[1]; 780 } 781 ViewCompat.setTranslationY(mContainerView, startingY); 782 ViewPropertyAnimatorCompatSet anim = new ViewPropertyAnimatorCompatSet(); 783 ViewPropertyAnimatorCompat a = ViewCompat.animate(mContainerView).translationY(0f); 784 a.setUpdateListener(mUpdateListener); 785 anim.play(a); 786 if (mContentAnimations && mContentView != null) { 787 ViewCompat.setTranslationY(mContentView, startingY); 788 anim.play(ViewCompat.animate(mContentView).translationY(0f)); 789 } 790 if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { 791 ViewCompat.setTranslationY(mSplitView, mSplitView.getHeight()); 792 mSplitView.setVisibility(View.VISIBLE); 793 anim.play(ViewCompat.animate(mSplitView).translationY(0f)); 794 } 795 anim.setInterpolator(AnimationUtils.loadInterpolator(mContext, 796 android.R.anim.decelerate_interpolator)); 797 anim.setDuration(250); 798 // If this is being shown from the system, add a small delay. 799 // This is because we will also be animating in the status bar, 800 // and these two elements can't be done in lock-step. So we give 801 // a little time for the status bar to start its animation before 802 // the action bar animates. (This corresponds to the corresponding 803 // case when hiding, where the status bar has a small delay before 804 // starting.) 805 anim.setListener(mShowListener); 806 mCurrentShowAnim = anim; 807 anim.start(); 808 } else { 809 ViewCompat.setAlpha(mContainerView, 1f); 810 ViewCompat.setTranslationY(mContainerView, 0); 811 if (mContentAnimations && mContentView != null) { 812 ViewCompat.setTranslationY(mContentView, 0); 813 } 814 if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { 815 ViewCompat.setAlpha(mSplitView, 1f); 816 ViewCompat.setTranslationY(mSplitView, 0); 817 mSplitView.setVisibility(View.VISIBLE); 818 } 819 mShowListener.onAnimationEnd(null); 820 } 821 if (mOverlayLayout != null) { 822 ViewCompat.requestApplyInsets(mOverlayLayout); 823 } 824 } 825 doHide(boolean fromSystem)826 public void doHide(boolean fromSystem) { 827 if (mCurrentShowAnim != null) { 828 mCurrentShowAnim.cancel(); 829 } 830 831 if (mCurWindowVisibility == View.VISIBLE && ALLOW_SHOW_HIDE_ANIMATIONS && 832 (mShowHideAnimationEnabled || fromSystem)) { 833 ViewCompat.setAlpha(mContainerView, 1f); 834 mContainerView.setTransitioning(true); 835 ViewPropertyAnimatorCompatSet anim = new ViewPropertyAnimatorCompatSet(); 836 float endingY = -mContainerView.getHeight(); 837 if (fromSystem) { 838 int topLeft[] = {0, 0}; 839 mContainerView.getLocationInWindow(topLeft); 840 endingY -= topLeft[1]; 841 } 842 ViewPropertyAnimatorCompat a = ViewCompat.animate(mContainerView).translationY(endingY); 843 a.setUpdateListener(mUpdateListener); 844 anim.play(a); 845 if (mContentAnimations && mContentView != null) { 846 anim.play(ViewCompat.animate(mContentView).translationY(endingY)); 847 } 848 if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) { 849 ViewCompat.setAlpha(mSplitView, 1f); 850 anim.play(ViewCompat.animate(mSplitView).translationY(mSplitView.getHeight())); 851 } 852 anim.setInterpolator(AnimationUtils.loadInterpolator(mContext, 853 android.R.anim.accelerate_interpolator)); 854 anim.setDuration(250); 855 anim.setListener(mHideListener); 856 mCurrentShowAnim = anim; 857 anim.start(); 858 } else { 859 mHideListener.onAnimationEnd(null); 860 } 861 } 862 isShowing()863 public boolean isShowing() { 864 final int height = getHeight(); 865 // Take into account the case where the bar has a 0 height due to not being measured yet. 866 return mNowShowing && (height == 0 || getHideOffset() < height); 867 } 868 animateToMode(boolean toActionMode)869 public void animateToMode(boolean toActionMode) { 870 if (toActionMode) { 871 showForActionMode(); 872 } else { 873 hideForActionMode(); 874 } 875 876 mDecorToolbar.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE); 877 mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE); 878 // mTabScrollView's visibility is not affected by action mode. 879 } 880 getThemedContext()881 public Context getThemedContext() { 882 if (mThemedContext == null) { 883 TypedValue outValue = new TypedValue(); 884 Resources.Theme currentTheme = mContext.getTheme(); 885 currentTheme.resolveAttribute(R.attr.actionBarWidgetTheme, outValue, true); 886 final int targetThemeRes = outValue.resourceId; 887 888 if (targetThemeRes != 0) { 889 mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes); 890 } else { 891 mThemedContext = mContext; 892 } 893 } 894 return mThemedContext; 895 } 896 897 @Override isTitleTruncated()898 public boolean isTitleTruncated() { 899 return mDecorToolbar != null && mDecorToolbar.isTitleTruncated(); 900 } 901 902 @Override setHomeAsUpIndicator(Drawable indicator)903 public void setHomeAsUpIndicator(Drawable indicator) { 904 mDecorToolbar.setNavigationIcon(indicator); 905 } 906 907 @Override setHomeAsUpIndicator(int resId)908 public void setHomeAsUpIndicator(int resId) { 909 mDecorToolbar.setNavigationIcon(resId); 910 } 911 912 @Override setHomeActionContentDescription(CharSequence description)913 public void setHomeActionContentDescription(CharSequence description) { 914 mDecorToolbar.setNavigationContentDescription(description); 915 } 916 917 @Override setHomeActionContentDescription(int resId)918 public void setHomeActionContentDescription(int resId) { 919 mDecorToolbar.setNavigationContentDescription(resId); 920 } 921 922 @Override onContentScrollStarted()923 public void onContentScrollStarted() { 924 if (mCurrentShowAnim != null) { 925 mCurrentShowAnim.cancel(); 926 mCurrentShowAnim = null; 927 } 928 } 929 930 @Override onContentScrollStopped()931 public void onContentScrollStopped() { 932 } 933 934 @Override collapseActionView()935 public boolean collapseActionView() { 936 if (mDecorToolbar != null && mDecorToolbar.hasExpandedActionView()) { 937 mDecorToolbar.collapseActionView(); 938 return true; 939 } 940 return false; 941 } 942 943 /** 944 * @hide 945 */ 946 public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback { 947 private final Context mActionModeContext; 948 private final MenuBuilder mMenu; 949 950 private ActionMode.Callback mCallback; 951 private WeakReference<View> mCustomView; 952 ActionModeImpl(Context context, ActionMode.Callback callback)953 public ActionModeImpl(Context context, ActionMode.Callback callback) { 954 mActionModeContext = context; 955 mCallback = callback; 956 mMenu = new MenuBuilder(context) 957 .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 958 mMenu.setCallback(this); 959 } 960 961 @Override getMenuInflater()962 public MenuInflater getMenuInflater() { 963 return new SupportMenuInflater(mActionModeContext); 964 } 965 966 @Override getMenu()967 public Menu getMenu() { 968 return mMenu; 969 } 970 971 @Override finish()972 public void finish() { 973 if (mActionMode != this) { 974 // Not the active action mode - no-op 975 return; 976 } 977 978 // If this change in state is going to cause the action bar 979 // to be hidden, defer the onDestroy callback until the animation 980 // is finished and associated relayout is about to happen. This lets 981 // apps better anticipate visibility and layout behavior. 982 if (!checkShowingFlags(mHiddenByApp, mHiddenBySystem, false)) { 983 // With the current state but the action bar hidden, our 984 // overall showing state is going to be false. 985 mDeferredDestroyActionMode = this; 986 mDeferredModeDestroyCallback = mCallback; 987 } else { 988 mCallback.onDestroyActionMode(this); 989 } 990 mCallback = null; 991 animateToMode(false); 992 993 // Clear out the context mode views after the animation finishes 994 mContextView.closeMode(); 995 mDecorToolbar.getViewGroup().sendAccessibilityEvent( 996 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 997 mOverlayLayout.setHideOnContentScrollEnabled(mHideOnContentScroll); 998 999 mActionMode = null; 1000 } 1001 1002 @Override invalidate()1003 public void invalidate() { 1004 mMenu.stopDispatchingItemsChanged(); 1005 try { 1006 mCallback.onPrepareActionMode(this, mMenu); 1007 } finally { 1008 mMenu.startDispatchingItemsChanged(); 1009 } 1010 } 1011 dispatchOnCreate()1012 public boolean dispatchOnCreate() { 1013 mMenu.stopDispatchingItemsChanged(); 1014 try { 1015 return mCallback.onCreateActionMode(this, mMenu); 1016 } finally { 1017 mMenu.startDispatchingItemsChanged(); 1018 } 1019 } 1020 1021 @Override setCustomView(View view)1022 public void setCustomView(View view) { 1023 mContextView.setCustomView(view); 1024 mCustomView = new WeakReference<View>(view); 1025 } 1026 1027 @Override setSubtitle(CharSequence subtitle)1028 public void setSubtitle(CharSequence subtitle) { 1029 mContextView.setSubtitle(subtitle); 1030 } 1031 1032 @Override setTitle(CharSequence title)1033 public void setTitle(CharSequence title) { 1034 mContextView.setTitle(title); 1035 } 1036 1037 @Override setTitle(int resId)1038 public void setTitle(int resId) { 1039 setTitle(mContext.getResources().getString(resId)); 1040 } 1041 1042 @Override setSubtitle(int resId)1043 public void setSubtitle(int resId) { 1044 setSubtitle(mContext.getResources().getString(resId)); 1045 } 1046 1047 @Override getTitle()1048 public CharSequence getTitle() { 1049 return mContextView.getTitle(); 1050 } 1051 1052 @Override getSubtitle()1053 public CharSequence getSubtitle() { 1054 return mContextView.getSubtitle(); 1055 } 1056 1057 @Override setTitleOptionalHint(boolean titleOptional)1058 public void setTitleOptionalHint(boolean titleOptional) { 1059 super.setTitleOptionalHint(titleOptional); 1060 mContextView.setTitleOptional(titleOptional); 1061 } 1062 1063 @Override isTitleOptional()1064 public boolean isTitleOptional() { 1065 return mContextView.isTitleOptional(); 1066 } 1067 1068 @Override getCustomView()1069 public View getCustomView() { 1070 return mCustomView != null ? mCustomView.get() : null; 1071 } 1072 onMenuItemSelected(MenuBuilder menu, MenuItem item)1073 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { 1074 if (mCallback != null) { 1075 return mCallback.onActionItemClicked(this, item); 1076 } else { 1077 return false; 1078 } 1079 } 1080 onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing)1081 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 1082 } 1083 onSubMenuSelected(SubMenuBuilder subMenu)1084 public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 1085 if (mCallback == null) { 1086 return false; 1087 } 1088 1089 if (!subMenu.hasVisibleItems()) { 1090 return true; 1091 } 1092 1093 new MenuPopupHelper(getThemedContext(), subMenu).show(); 1094 return true; 1095 } 1096 onCloseSubMenu(SubMenuBuilder menu)1097 public void onCloseSubMenu(SubMenuBuilder menu) { 1098 } 1099 onMenuModeChange(MenuBuilder menu)1100 public void onMenuModeChange(MenuBuilder menu) { 1101 if (mCallback == null) { 1102 return; 1103 } 1104 invalidate(); 1105 mContextView.showOverflowMenu(); 1106 } 1107 } 1108 1109 /** 1110 * @hide 1111 */ 1112 public class TabImpl extends ActionBar.Tab { 1113 private ActionBar.TabListener mCallback; 1114 private Object mTag; 1115 private Drawable mIcon; 1116 private CharSequence mText; 1117 private CharSequence mContentDesc; 1118 private int mPosition = -1; 1119 private View mCustomView; 1120 1121 @Override getTag()1122 public Object getTag() { 1123 return mTag; 1124 } 1125 1126 @Override setTag(Object tag)1127 public Tab setTag(Object tag) { 1128 mTag = tag; 1129 return this; 1130 } 1131 getCallback()1132 public ActionBar.TabListener getCallback() { 1133 return mCallback; 1134 } 1135 1136 @Override setTabListener(ActionBar.TabListener callback)1137 public Tab setTabListener(ActionBar.TabListener callback) { 1138 mCallback = callback; 1139 return this; 1140 } 1141 1142 @Override getCustomView()1143 public View getCustomView() { 1144 return mCustomView; 1145 } 1146 1147 @Override setCustomView(View view)1148 public Tab setCustomView(View view) { 1149 mCustomView = view; 1150 if (mPosition >= 0) { 1151 mTabScrollView.updateTab(mPosition); 1152 } 1153 return this; 1154 } 1155 1156 @Override setCustomView(int layoutResId)1157 public Tab setCustomView(int layoutResId) { 1158 return setCustomView(LayoutInflater.from(getThemedContext()) 1159 .inflate(layoutResId, null)); 1160 } 1161 1162 @Override getIcon()1163 public Drawable getIcon() { 1164 return mIcon; 1165 } 1166 1167 @Override getPosition()1168 public int getPosition() { 1169 return mPosition; 1170 } 1171 setPosition(int position)1172 public void setPosition(int position) { 1173 mPosition = position; 1174 } 1175 1176 @Override getText()1177 public CharSequence getText() { 1178 return mText; 1179 } 1180 1181 @Override setIcon(Drawable icon)1182 public Tab setIcon(Drawable icon) { 1183 mIcon = icon; 1184 if (mPosition >= 0) { 1185 mTabScrollView.updateTab(mPosition); 1186 } 1187 return this; 1188 } 1189 1190 @Override setIcon(int resId)1191 public Tab setIcon(int resId) { 1192 return setIcon(getTintManager().getDrawable(resId)); 1193 } 1194 1195 @Override setText(CharSequence text)1196 public Tab setText(CharSequence text) { 1197 mText = text; 1198 if (mPosition >= 0) { 1199 mTabScrollView.updateTab(mPosition); 1200 } 1201 return this; 1202 } 1203 1204 @Override setText(int resId)1205 public Tab setText(int resId) { 1206 return setText(mContext.getResources().getText(resId)); 1207 } 1208 1209 @Override select()1210 public void select() { 1211 selectTab(this); 1212 } 1213 1214 @Override setContentDescription(int resId)1215 public Tab setContentDescription(int resId) { 1216 return setContentDescription(mContext.getResources().getText(resId)); 1217 } 1218 1219 @Override setContentDescription(CharSequence contentDesc)1220 public Tab setContentDescription(CharSequence contentDesc) { 1221 mContentDesc = contentDesc; 1222 if (mPosition >= 0) { 1223 mTabScrollView.updateTab(mPosition); 1224 } 1225 return this; 1226 } 1227 1228 @Override getContentDescription()1229 public CharSequence getContentDescription() { 1230 return mContentDesc; 1231 } 1232 } 1233 1234 @Override setCustomView(View view)1235 public void setCustomView(View view) { 1236 mDecorToolbar.setCustomView(view); 1237 } 1238 1239 @Override setCustomView(View view, LayoutParams layoutParams)1240 public void setCustomView(View view, LayoutParams layoutParams) { 1241 view.setLayoutParams(layoutParams); 1242 mDecorToolbar.setCustomView(view); 1243 } 1244 1245 @Override setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback)1246 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) { 1247 mDecorToolbar.setDropdownParams(adapter, new NavItemSelectedListener(callback)); 1248 } 1249 1250 @Override getSelectedNavigationIndex()1251 public int getSelectedNavigationIndex() { 1252 switch (mDecorToolbar.getNavigationMode()) { 1253 case NAVIGATION_MODE_TABS: 1254 return mSelectedTab != null ? mSelectedTab.getPosition() : -1; 1255 case NAVIGATION_MODE_LIST: 1256 return mDecorToolbar.getDropdownSelectedPosition(); 1257 default: 1258 return -1; 1259 } 1260 } 1261 1262 @Override getNavigationItemCount()1263 public int getNavigationItemCount() { 1264 switch (mDecorToolbar.getNavigationMode()) { 1265 case NAVIGATION_MODE_TABS: 1266 return mTabs.size(); 1267 case NAVIGATION_MODE_LIST: 1268 return mDecorToolbar.getDropdownItemCount(); 1269 default: 1270 return 0; 1271 } 1272 } 1273 1274 @Override getTabCount()1275 public int getTabCount() { 1276 return mTabs.size(); 1277 } 1278 1279 @Override setNavigationMode(int mode)1280 public void setNavigationMode(int mode) { 1281 final int oldMode = mDecorToolbar.getNavigationMode(); 1282 switch (oldMode) { 1283 case NAVIGATION_MODE_TABS: 1284 mSavedTabPosition = getSelectedNavigationIndex(); 1285 selectTab(null); 1286 mTabScrollView.setVisibility(View.GONE); 1287 break; 1288 } 1289 if (oldMode != mode && !mHasEmbeddedTabs) { 1290 if (mOverlayLayout != null) { 1291 ViewCompat.requestApplyInsets(mOverlayLayout); 1292 } 1293 } 1294 mDecorToolbar.setNavigationMode(mode); 1295 switch (mode) { 1296 case NAVIGATION_MODE_TABS: 1297 ensureTabsExist(); 1298 mTabScrollView.setVisibility(View.VISIBLE); 1299 if (mSavedTabPosition != INVALID_POSITION) { 1300 setSelectedNavigationItem(mSavedTabPosition); 1301 mSavedTabPosition = INVALID_POSITION; 1302 } 1303 break; 1304 } 1305 mDecorToolbar.setCollapsible(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs); 1306 mOverlayLayout.setHasNonEmbeddedTabs(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs); 1307 } 1308 1309 @Override getTabAt(int index)1310 public Tab getTabAt(int index) { 1311 return mTabs.get(index); 1312 } 1313 1314 1315 @Override setIcon(int resId)1316 public void setIcon(int resId) { 1317 mDecorToolbar.setIcon(resId); 1318 } 1319 1320 @Override setIcon(Drawable icon)1321 public void setIcon(Drawable icon) { 1322 mDecorToolbar.setIcon(icon); 1323 } 1324 hasIcon()1325 public boolean hasIcon() { 1326 return mDecorToolbar.hasIcon(); 1327 } 1328 1329 @Override setLogo(int resId)1330 public void setLogo(int resId) { 1331 mDecorToolbar.setLogo(resId); 1332 } 1333 1334 @Override setLogo(Drawable logo)1335 public void setLogo(Drawable logo) { 1336 mDecorToolbar.setLogo(logo); 1337 } 1338 hasLogo()1339 public boolean hasLogo() { 1340 return mDecorToolbar.hasLogo(); 1341 } 1342 setDefaultDisplayHomeAsUpEnabled(boolean enable)1343 public void setDefaultDisplayHomeAsUpEnabled(boolean enable) { 1344 if (!mDisplayHomeAsUpSet) { 1345 setDisplayHomeAsUpEnabled(enable); 1346 } 1347 } 1348 getTintManager()1349 TintManager getTintManager() { 1350 if (mTintManager == null) { 1351 mTintManager = new TintManager(mContext); 1352 } 1353 return mTintManager; 1354 } 1355 1356 } 1357