1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v7.app; 18 19import android.app.Dialog; 20import android.content.Context; 21import android.content.res.Configuration; 22import android.content.res.Resources; 23import android.graphics.drawable.Drawable; 24import android.os.Handler; 25import android.support.v4.app.FragmentTransaction; 26import android.support.v7.appcompat.R; 27import android.support.v7.internal.view.ActionBarPolicy; 28import android.support.v7.internal.view.SupportMenuInflater; 29import android.support.v7.internal.view.menu.MenuBuilder; 30import android.support.v7.internal.view.menu.SubMenuBuilder; 31import android.support.v7.internal.widget.ActionBarContainer; 32import android.support.v7.internal.widget.ActionBarContextView; 33import android.support.v7.internal.widget.ActionBarOverlayLayout; 34import android.support.v7.internal.widget.ActionBarView; 35import android.support.v7.internal.widget.ScrollingTabContainerView; 36import android.support.v7.view.ActionMode; 37import android.support.v4.internal.view.SupportMenuItem; 38import android.util.TypedValue; 39import android.view.ContextThemeWrapper; 40import android.view.LayoutInflater; 41import android.view.Menu; 42import android.view.MenuInflater; 43import android.view.MenuItem; 44import android.view.View; 45import android.view.ViewGroup; 46import android.view.accessibility.AccessibilityEvent; 47import android.view.animation.Animation; 48import android.view.animation.AnimationUtils; 49import android.widget.SpinnerAdapter; 50 51import java.lang.ref.WeakReference; 52import java.util.ArrayList; 53 54class ActionBarImplBase extends ActionBar { 55 private Context mContext; 56 private Context mThemedContext; 57 private ActionBarActivity mActivity; 58 private Dialog mDialog; 59 60 private ActionBarOverlayLayout mOverlayLayout; 61 private ActionBarContainer mContainerView; 62 private ViewGroup mTopVisibilityView; 63 private ActionBarView mActionView; 64 private ActionBarContextView mContextView; 65 private ActionBarContainer mSplitView; 66 private View mContentView; 67 private ScrollingTabContainerView mTabScrollView; 68 69 private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>(); 70 71 private TabImpl mSelectedTab; 72 private int mSavedTabPosition = INVALID_POSITION; 73 74 private boolean mDisplayHomeAsUpSet; 75 76 ActionModeImpl mActionMode; 77 ActionMode mDeferredDestroyActionMode; 78 ActionMode.Callback mDeferredModeDestroyCallback; 79 80 private boolean mLastMenuVisibility; 81 private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners = 82 new ArrayList<OnMenuVisibilityListener>(); 83 84 private static final int CONTEXT_DISPLAY_NORMAL = 0; 85 private static final int CONTEXT_DISPLAY_SPLIT = 1; 86 87 private static final int INVALID_POSITION = -1; 88 89 private int mContextDisplayMode; 90 private boolean mHasEmbeddedTabs; 91 92 final Handler mHandler = new Handler(); 93 Runnable mTabSelector; 94 95 private int mCurWindowVisibility = View.VISIBLE; 96 97 private boolean mHiddenByApp; 98 private boolean mHiddenBySystem; 99 private boolean mShowingForMode; 100 101 private boolean mNowShowing = true; 102 private boolean mShowHideAnimationEnabled; 103 104 private Callback mCallback; 105 106 public ActionBarImplBase(ActionBarActivity activity, Callback callback) { 107 mActivity = activity; 108 mContext = activity; 109 mCallback = callback; 110 init(mActivity); 111 } 112 113 private void init(ActionBarActivity activity) { 114 mOverlayLayout = (ActionBarOverlayLayout) activity.findViewById( 115 R.id.action_bar_overlay_layout); 116 if (mOverlayLayout != null) { 117 mOverlayLayout.setActionBar(this); 118 } 119 mActionView = (ActionBarView) activity.findViewById(R.id.action_bar); 120 mContextView = (ActionBarContextView) activity.findViewById(R.id.action_context_bar); 121 mContainerView = (ActionBarContainer) activity.findViewById(R.id.action_bar_container); 122 mTopVisibilityView = (ViewGroup) activity.findViewById(R.id.top_action_bar); 123 if (mTopVisibilityView == null) { 124 mTopVisibilityView = mContainerView; 125 } 126 mSplitView = (ActionBarContainer) activity.findViewById(R.id.split_action_bar); 127 128 if (mActionView == null || mContextView == null || mContainerView == null) { 129 throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 130 "with a compatible window decor layout"); 131 } 132 133 mActionView.setContextView(mContextView); 134 mContextDisplayMode = mActionView.isSplitActionBar() ? 135 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; 136 137 // This was initially read from the action bar style 138 final int current = mActionView.getDisplayOptions(); 139 final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0; 140 if (homeAsUp) { 141 mDisplayHomeAsUpSet = true; 142 } 143 144 ActionBarPolicy abp = ActionBarPolicy.get(mContext); 145 setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp); 146 setHasEmbeddedTabs(abp.hasEmbeddedTabs()); 147 setTitle(mActivity.getTitle()); 148 } 149 150 public void onConfigurationChanged(Configuration newConfig) { 151 setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs()); 152 } 153 154 private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) { 155 mHasEmbeddedTabs = hasEmbeddedTabs; 156 // Switch tab layout configuration if needed 157 if (!mHasEmbeddedTabs) { 158 mActionView.setEmbeddedTabView(null); 159 mContainerView.setTabContainer(mTabScrollView); 160 } else { 161 mContainerView.setTabContainer(null); 162 mActionView.setEmbeddedTabView(mTabScrollView); 163 } 164 final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS; 165 if (mTabScrollView != null) { 166 if (isInTabMode) { 167 mTabScrollView.setVisibility(View.VISIBLE); 168 } else { 169 mTabScrollView.setVisibility(View.GONE); 170 } 171 } 172 mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode); 173 } 174 175 public boolean hasNonEmbeddedTabs() { 176 return !mHasEmbeddedTabs && getNavigationMode() == NAVIGATION_MODE_TABS; 177 } 178 179 @Override 180 public void setCustomView(View view) { 181 mActionView.setCustomNavigationView(view); 182 } 183 184 @Override 185 public void setCustomView(View view, LayoutParams layoutParams) { 186 view.setLayoutParams(layoutParams); 187 mActionView.setCustomNavigationView(view); 188 189 } 190 191 @Override 192 public void setCustomView(int resId) { 193 setCustomView(LayoutInflater.from(getThemedContext()) 194 .inflate(resId, mActionView, false)); 195 } 196 197 @Override 198 public void setIcon(int resId) { 199 mActionView.setIcon(resId); 200 } 201 202 @Override 203 public void setIcon(Drawable icon) { 204 mActionView.setIcon(icon); 205 } 206 207 @Override 208 public void setLogo(int resId) { 209 mActionView.setLogo(resId); 210 } 211 212 @Override 213 public void setLogo(Drawable logo) { 214 mActionView.setLogo(logo); 215 } 216 217 @Override 218 public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) { 219 mActionView.setDropdownAdapter(adapter); 220 mActionView.setCallback(callback); 221 } 222 223 @Override 224 public void setSelectedNavigationItem(int position) { 225 switch (mActionView.getNavigationMode()) { 226 case NAVIGATION_MODE_TABS: 227 selectTab(mTabs.get(position)); 228 break; 229 case NAVIGATION_MODE_LIST: 230 mActionView.setDropdownSelectedPosition(position); 231 break; 232 default: 233 throw new IllegalStateException( 234 "setSelectedNavigationIndex not valid for current navigation mode"); 235 } 236 } 237 238 @Override 239 public int getSelectedNavigationIndex() { 240 switch (mActionView.getNavigationMode()) { 241 case NAVIGATION_MODE_TABS: 242 return mSelectedTab != null ? mSelectedTab.getPosition() : -1; 243 case NAVIGATION_MODE_LIST: 244 return mActionView.getDropdownSelectedPosition(); 245 default: 246 return -1; 247 } 248 } 249 250 @Override 251 public int getNavigationItemCount() { 252 switch (mActionView.getNavigationMode()) { 253 case NAVIGATION_MODE_TABS: 254 return mTabs.size(); 255 case NAVIGATION_MODE_LIST: 256 SpinnerAdapter adapter = mActionView.getDropdownAdapter(); 257 return adapter != null ? adapter.getCount() : 0; 258 default: 259 return 0; 260 } 261 } 262 263 @Override 264 public void setTitle(CharSequence title) { 265 mActionView.setTitle(title); 266 } 267 268 @Override 269 public void setTitle(int resId) { 270 setTitle(mContext.getString(resId)); 271 } 272 273 @Override 274 public void setSubtitle(CharSequence subtitle) { 275 mActionView.setSubtitle(subtitle); 276 } 277 278 @Override 279 public void setSubtitle(int resId) { 280 setSubtitle(mContext.getString(resId)); 281 } 282 283 @Override 284 public void setDisplayOptions(int options) { 285 if ((options & DISPLAY_HOME_AS_UP) != 0) { 286 mDisplayHomeAsUpSet = true; 287 } 288 mActionView.setDisplayOptions(options); 289 } 290 291 @Override 292 public void setDisplayOptions(int options, int mask) { 293 final int current = mActionView.getDisplayOptions(); 294 if ((mask & DISPLAY_HOME_AS_UP) != 0) { 295 mDisplayHomeAsUpSet = true; 296 } 297 mActionView.setDisplayOptions((options & mask) | (current & ~mask)); 298 } 299 300 @Override 301 public void setDisplayUseLogoEnabled(boolean useLogo) { 302 setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO); 303 } 304 305 @Override 306 public void setDisplayShowHomeEnabled(boolean showHome) { 307 setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME); 308 } 309 310 @Override 311 public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { 312 setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP); 313 } 314 315 @Override 316 public void setDisplayShowTitleEnabled(boolean showTitle) { 317 setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE); 318 } 319 320 @Override 321 public void setDisplayShowCustomEnabled(boolean showCustom) { 322 setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM); 323 } 324 325 @Override 326 public void setHomeButtonEnabled(boolean enable) { 327 mActionView.setHomeButtonEnabled(enable); 328 } 329 330 @Override 331 public void setBackgroundDrawable(Drawable d) { 332 mContainerView.setPrimaryBackground(d); 333 } 334 335 @Override 336 public View getCustomView() { 337 return mActionView.getCustomNavigationView(); 338 } 339 340 @Override 341 public CharSequence getTitle() { 342 return mActionView.getTitle(); 343 } 344 345 @Override 346 public CharSequence getSubtitle() { 347 return mActionView.getSubtitle(); 348 } 349 350 @Override 351 public int getNavigationMode() { 352 return mActionView.getNavigationMode(); 353 } 354 355 @Override 356 public void setNavigationMode(int mode) { 357 final int oldMode = mActionView.getNavigationMode(); 358 switch (oldMode) { 359 case NAVIGATION_MODE_TABS: 360 mSavedTabPosition = getSelectedNavigationIndex(); 361 selectTab(null); 362 mTabScrollView.setVisibility(View.GONE); 363 break; 364 } 365 mActionView.setNavigationMode(mode); 366 switch (mode) { 367 case NAVIGATION_MODE_TABS: 368 ensureTabsExist(); 369 mTabScrollView.setVisibility(View.VISIBLE); 370 if (mSavedTabPosition != INVALID_POSITION) { 371 setSelectedNavigationItem(mSavedTabPosition); 372 mSavedTabPosition = INVALID_POSITION; 373 } 374 break; 375 } 376 mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs); 377 } 378 379 @Override 380 public int getDisplayOptions() { 381 return mActionView.getDisplayOptions(); 382 } 383 384 @Override 385 public Tab newTab() { 386 return new TabImpl(); 387 } 388 389 @Override 390 public void addTab(Tab tab) { 391 addTab(tab, mTabs.isEmpty()); 392 } 393 394 @Override 395 public void addTab(Tab tab, boolean setSelected) { 396 ensureTabsExist(); 397 mTabScrollView.addTab(tab, setSelected); 398 configureTab(tab, mTabs.size()); 399 if (setSelected) { 400 selectTab(tab); 401 } 402 } 403 404 @Override 405 public void addTab(Tab tab, int position) { 406 addTab(tab, position, mTabs.isEmpty()); 407 } 408 409 @Override 410 public void addTab(Tab tab, int position, boolean setSelected) { 411 ensureTabsExist(); 412 mTabScrollView.addTab(tab, position, setSelected); 413 configureTab(tab, position); 414 if (setSelected) { 415 selectTab(tab); 416 } 417 } 418 419 @Override 420 public void removeTab(Tab tab) { 421 removeTabAt(tab.getPosition()); 422 } 423 424 @Override 425 public void removeTabAt(int position) { 426 if (mTabScrollView == null) { 427 // No tabs around to remove 428 return; 429 } 430 431 int selectedTabPosition = mSelectedTab != null 432 ? mSelectedTab.getPosition() : mSavedTabPosition; 433 mTabScrollView.removeTabAt(position); 434 TabImpl removedTab = mTabs.remove(position); 435 if (removedTab != null) { 436 removedTab.setPosition(-1); 437 } 438 439 final int newTabCount = mTabs.size(); 440 for (int i = position; i < newTabCount; i++) { 441 mTabs.get(i).setPosition(i); 442 } 443 444 if (selectedTabPosition == position) { 445 selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1))); 446 } 447 } 448 449 @Override 450 public void removeAllTabs() { 451 cleanupTabs(); 452 } 453 454 @Override 455 public void selectTab(Tab tab) { 456 if (getNavigationMode() != NAVIGATION_MODE_TABS) { 457 mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION; 458 return; 459 } 460 461 final FragmentTransaction trans = mActivity.getSupportFragmentManager().beginTransaction() 462 .disallowAddToBackStack(); 463 464 if (mSelectedTab == tab) { 465 if (mSelectedTab != null) { 466 mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans); 467 mTabScrollView.animateToTab(tab.getPosition()); 468 } 469 } else { 470 mTabScrollView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION); 471 if (mSelectedTab != null) { 472 mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans); 473 } 474 mSelectedTab = (TabImpl) tab; 475 if (mSelectedTab != null) { 476 mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans); 477 } 478 } 479 480 if (!trans.isEmpty()) { 481 trans.commit(); 482 } 483 } 484 485 @Override 486 public Tab getSelectedTab() { 487 return mSelectedTab; 488 } 489 490 @Override 491 public Tab getTabAt(int index) { 492 return mTabs.get(index); 493 } 494 495 @Override 496 public int getTabCount() { 497 return mTabs.size(); 498 } 499 500 @Override 501 public Context getThemedContext() { 502 if (mThemedContext == null) { 503 TypedValue outValue = new TypedValue(); 504 Resources.Theme currentTheme = mContext.getTheme(); 505 currentTheme.resolveAttribute(R.attr.actionBarWidgetTheme, outValue, true); 506 final int targetThemeRes = outValue.resourceId; 507 508 if (targetThemeRes != 0) { 509 mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes); 510 } else { 511 mThemedContext = mContext; 512 } 513 } 514 return mThemedContext; 515 } 516 517 @Override 518 public int getHeight() { 519 return mContainerView.getHeight(); 520 } 521 522 @Override 523 public void show() { 524 if (mHiddenByApp) { 525 mHiddenByApp = false; 526 updateVisibility(false); 527 } 528 } 529 530 void showForActionMode() { 531 if (!mShowingForMode) { 532 mShowingForMode = true; 533 updateVisibility(false); 534 } 535 } 536 537 @Override 538 public void hide() { 539 if (!mHiddenByApp) { 540 mHiddenByApp = true; 541 updateVisibility(false); 542 } 543 } 544 545 void hideForActionMode() { 546 if (mShowingForMode) { 547 mShowingForMode = false; 548 updateVisibility(false); 549 } 550 } 551 552 @Override 553 public boolean isShowing() { 554 return mNowShowing; 555 } 556 557 @Override 558 public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { 559 mMenuVisibilityListeners.add(listener); 560 } 561 562 @Override 563 public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) { 564 mMenuVisibilityListeners.remove(listener); 565 } 566 567 public ActionMode startActionMode(ActionMode.Callback callback) { 568 if (mActionMode != null) { 569 mActionMode.finish(); 570 } 571 572 mContextView.killMode(); 573 ActionModeImpl mode = new ActionModeImpl(callback); 574 if (mode.dispatchOnCreate()) { 575 mode.invalidate(); 576 mContextView.initForMode(mode); 577 animateToMode(true); 578 if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { 579 if (mSplitView.getVisibility() != View.VISIBLE) { 580 mSplitView.setVisibility(View.VISIBLE); 581 } 582 } 583 mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 584 mActionMode = mode; 585 return mode; 586 } 587 return null; 588 } 589 590 void animateToMode(boolean toActionMode) { 591 if (toActionMode) { 592 showForActionMode(); 593 } else { 594 hideForActionMode(); 595 } 596 597 mActionView.animateToVisibility(toActionMode ? View.INVISIBLE : View.VISIBLE); 598 mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE); 599 if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) { 600 mTabScrollView.setVisibility(toActionMode ? View.GONE : View.VISIBLE); 601 } 602 } 603 604 /** 605 * @hide 606 */ 607 public class TabImpl extends ActionBar.Tab { 608 609 private ActionBar.TabListener mCallback; 610 private Object mTag; 611 private Drawable mIcon; 612 private CharSequence mText; 613 private CharSequence mContentDesc; 614 private int mPosition = -1; 615 private View mCustomView; 616 617 @Override 618 public Object getTag() { 619 return mTag; 620 } 621 622 @Override 623 public Tab setTag(Object tag) { 624 mTag = tag; 625 return this; 626 } 627 628 public ActionBar.TabListener getCallback() { 629 return mCallback; 630 } 631 632 @Override 633 public Tab setTabListener(ActionBar.TabListener callback) { 634 mCallback = callback; 635 return this; 636 } 637 638 @Override 639 public View getCustomView() { 640 return mCustomView; 641 } 642 643 @Override 644 public Tab setCustomView(View view) { 645 mCustomView = view; 646 if (mPosition >= 0) { 647 mTabScrollView.updateTab(mPosition); 648 } 649 return this; 650 } 651 652 @Override 653 public Tab setCustomView(int layoutResId) { 654 return setCustomView(LayoutInflater.from(getThemedContext()) 655 .inflate(layoutResId, null)); 656 } 657 658 @Override 659 public Drawable getIcon() { 660 return mIcon; 661 } 662 663 @Override 664 public int getPosition() { 665 return mPosition; 666 } 667 668 public void setPosition(int position) { 669 mPosition = position; 670 } 671 672 @Override 673 public CharSequence getText() { 674 return mText; 675 } 676 677 @Override 678 public Tab setIcon(Drawable icon) { 679 mIcon = icon; 680 if (mPosition >= 0) { 681 mTabScrollView.updateTab(mPosition); 682 } 683 return this; 684 } 685 686 @Override 687 public Tab setIcon(int resId) { 688 return setIcon(mContext.getResources().getDrawable(resId)); 689 } 690 691 @Override 692 public Tab setText(CharSequence text) { 693 mText = text; 694 if (mPosition >= 0) { 695 mTabScrollView.updateTab(mPosition); 696 } 697 return this; 698 } 699 700 @Override 701 public Tab setText(int resId) { 702 return setText(mContext.getResources().getText(resId)); 703 } 704 705 @Override 706 public void select() { 707 selectTab(this); 708 } 709 710 @Override 711 public Tab setContentDescription(int resId) { 712 return setContentDescription(mContext.getResources().getText(resId)); 713 } 714 715 @Override 716 public Tab setContentDescription(CharSequence contentDesc) { 717 mContentDesc = contentDesc; 718 if (mPosition >= 0) { 719 mTabScrollView.updateTab(mPosition); 720 } 721 return this; 722 } 723 724 @Override 725 public CharSequence getContentDescription() { 726 return mContentDesc; 727 } 728 } 729 730 class ActionModeImpl extends ActionMode implements MenuBuilder.Callback { 731 732 private ActionMode.Callback mCallback; 733 private MenuBuilder mMenu; 734 private WeakReference<View> mCustomView; 735 736 public ActionModeImpl(ActionMode.Callback callback) { 737 mCallback = callback; 738 mMenu = new MenuBuilder(getThemedContext()) 739 .setDefaultShowAsAction(SupportMenuItem.SHOW_AS_ACTION_IF_ROOM); 740 mMenu.setCallback(this); 741 } 742 743 @Override 744 public MenuInflater getMenuInflater() { 745 return new SupportMenuInflater(getThemedContext()); 746 } 747 748 @Override 749 public Menu getMenu() { 750 return mMenu; 751 } 752 753 @Override 754 public void finish() { 755 if (mActionMode != this) { 756 // Not the active action mode - no-op 757 return; 758 } 759 760 // If this change in state is going to cause the action bar 761 // to be hidden, defer the onDestroy callback until the animation 762 // is finished and associated relayout is about to happen. This lets 763 // apps better anticipate visibility and layout behavior. 764 if (!checkShowingFlags(mHiddenByApp, mHiddenBySystem, false)) { 765 // With the current state but the action bar hidden, our 766 // overall showing state is going to be false. 767 mDeferredDestroyActionMode = this; 768 mDeferredModeDestroyCallback = mCallback; 769 } else { 770 mCallback.onDestroyActionMode(this); 771 } 772 mCallback = null; 773 animateToMode(false); 774 775 // Clear out the context mode views after the animation finishes 776 mContextView.closeMode(); 777 mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 778 779 mActionMode = null; 780 } 781 782 @Override 783 public void invalidate() { 784 mMenu.stopDispatchingItemsChanged(); 785 try { 786 mCallback.onPrepareActionMode(this, mMenu); 787 } finally { 788 mMenu.startDispatchingItemsChanged(); 789 } 790 } 791 792 public boolean dispatchOnCreate() { 793 mMenu.stopDispatchingItemsChanged(); 794 try { 795 return mCallback.onCreateActionMode(this, mMenu); 796 } finally { 797 mMenu.startDispatchingItemsChanged(); 798 } 799 } 800 801 @Override 802 public void setCustomView(View view) { 803 mContextView.setCustomView(view); 804 mCustomView = new WeakReference<View>(view); 805 } 806 807 @Override 808 public void setSubtitle(CharSequence subtitle) { 809 mContextView.setSubtitle(subtitle); 810 } 811 812 @Override 813 public void setTitle(CharSequence title) { 814 mContextView.setTitle(title); 815 } 816 817 @Override 818 public void setTitle(int resId) { 819 setTitle(mContext.getResources().getString(resId)); 820 } 821 822 @Override 823 public void setSubtitle(int resId) { 824 setSubtitle(mContext.getResources().getString(resId)); 825 } 826 827 @Override 828 public CharSequence getTitle() { 829 return mContextView.getTitle(); 830 } 831 832 @Override 833 public CharSequence getSubtitle() { 834 return mContextView.getSubtitle(); 835 } 836 837 @Override 838 public void setTitleOptionalHint(boolean titleOptional) { 839 super.setTitleOptionalHint(titleOptional); 840 mContextView.setTitleOptional(titleOptional); 841 } 842 843 @Override 844 public boolean isTitleOptional() { 845 return mContextView.isTitleOptional(); 846 } 847 848 @Override 849 public View getCustomView() { 850 return mCustomView != null ? mCustomView.get() : null; 851 } 852 853 public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { 854 if (mCallback != null) { 855 return mCallback.onActionItemClicked(this, item); 856 } else { 857 return false; 858 } 859 } 860 861 @Override 862 public void onMenuModeChange(MenuBuilder menu) { 863 if (mCallback == null) { 864 return; 865 } 866 invalidate(); 867 mContextView.showOverflowMenu(); 868 } 869 870 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 871 } 872 873 public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 874 if (mCallback == null) { 875 return false; 876 } 877 878 if (!subMenu.hasVisibleItems()) { 879 return true; 880 } 881 882 //new MenuPopupHelper(getThemedContext(), subMenu).show(); 883 return true; 884 } 885 886 public void onCloseSubMenu(SubMenuBuilder menu) { 887 } 888 889 public void onMenuModeChange(Menu menu) { 890 if (mCallback == null) { 891 return; 892 } 893 invalidate(); 894 mContextView.showOverflowMenu(); 895 } 896 } 897 898 private void ensureTabsExist() { 899 if (mTabScrollView != null) { 900 return; 901 } 902 903 ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext); 904 905 if (mHasEmbeddedTabs) { 906 tabScroller.setVisibility(View.VISIBLE); 907 mActionView.setEmbeddedTabView(tabScroller); 908 } else { 909 if (getNavigationMode() == NAVIGATION_MODE_TABS) { 910 tabScroller.setVisibility(View.VISIBLE); 911 } else { 912 tabScroller.setVisibility(View.GONE); 913 } 914 mContainerView.setTabContainer(tabScroller); 915 } 916 mTabScrollView = tabScroller; 917 } 918 919 private void configureTab(Tab tab, int position) { 920 final TabImpl tabi = (TabImpl) tab; 921 final ActionBar.TabListener callback = tabi.getCallback(); 922 923 if (callback == null) { 924 throw new IllegalStateException("Action Bar Tab must have a Callback"); 925 } 926 927 tabi.setPosition(position); 928 mTabs.add(position, tabi); 929 930 final int count = mTabs.size(); 931 for (int i = position + 1; i < count; i++) { 932 mTabs.get(i).setPosition(i); 933 } 934 } 935 936 private void cleanupTabs() { 937 if (mSelectedTab != null) { 938 selectTab(null); 939 } 940 mTabs.clear(); 941 if (mTabScrollView != null) { 942 mTabScrollView.removeAllTabs(); 943 } 944 mSavedTabPosition = INVALID_POSITION; 945 } 946 947 private static boolean checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem, 948 boolean showingForMode) { 949 if (showingForMode) { 950 return true; 951 } else if (hiddenByApp || hiddenBySystem) { 952 return false; 953 } else { 954 return true; 955 } 956 } 957 958 private void updateVisibility(boolean fromSystem) { 959 // Based on the current state, should we be hidden or shown? 960 final boolean shown = checkShowingFlags(mHiddenByApp, mHiddenBySystem, mShowingForMode); 961 962 if (shown) { 963 if (!mNowShowing) { 964 mNowShowing = true; 965 doShow(fromSystem); 966 } 967 } else { 968 if (mNowShowing) { 969 mNowShowing = false; 970 doHide(fromSystem); 971 } 972 } 973 } 974 975 public void setShowHideAnimationEnabled(boolean enabled) { 976 mShowHideAnimationEnabled = enabled; 977 if (!enabled) { 978 mTopVisibilityView.clearAnimation(); 979 if (mSplitView != null) { 980 mSplitView.clearAnimation(); 981 } 982 } 983 } 984 985 public void doShow(boolean fromSystem) { 986 mTopVisibilityView.clearAnimation(); 987 if (mTopVisibilityView.getVisibility() == View.VISIBLE) { 988 return; 989 } 990 991 final boolean animate = isShowHideAnimationEnabled() || fromSystem; 992 993 if (animate) { 994 Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.abc_slide_in_top); 995 mTopVisibilityView.startAnimation(anim); 996 } 997 mTopVisibilityView.setVisibility(View.VISIBLE); 998 999 if (mSplitView != null && mSplitView.getVisibility() != View.VISIBLE) { 1000 if (animate) { 1001 Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.abc_slide_in_bottom); 1002 mSplitView.startAnimation(anim); 1003 } 1004 mSplitView.setVisibility(View.VISIBLE); 1005 } 1006 } 1007 1008 public void doHide(boolean fromSystem) { 1009 mTopVisibilityView.clearAnimation(); 1010 if (mTopVisibilityView.getVisibility() == View.GONE) { 1011 return; 1012 } 1013 1014 final boolean animate = isShowHideAnimationEnabled() || fromSystem; 1015 1016 if (animate) { 1017 Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.abc_slide_out_top); 1018 mTopVisibilityView.startAnimation(anim); 1019 } 1020 mTopVisibilityView.setVisibility(View.GONE); 1021 1022 if (mSplitView != null && mSplitView.getVisibility() != View.GONE) { 1023 if (animate) { 1024 Animation anim = AnimationUtils 1025 .loadAnimation(mContext, R.anim.abc_slide_out_bottom); 1026 mSplitView.startAnimation(anim); 1027 } 1028 mSplitView.setVisibility(View.GONE); 1029 } 1030 } 1031 1032 boolean isShowHideAnimationEnabled() { 1033 return mShowHideAnimationEnabled; 1034 } 1035 1036} 1037