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