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