content: /*
   * Copyright (C) 2010 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.actionbarsherlock.internal.app;
  
  import java.lang.ref.WeakReference;
  import java.util.ArrayList;
  import android.app.Activity;
  import android.app.Dialog;
  import android.content.Context;
  import android.content.res.Configuration;
  import android.content.res.Resources;
  import android.graphics.drawable.Drawable;
  import android.os.Build;
  import android.os.Handler;
  import android.support.v4.app.FragmentActivity;
  import android.support.v4.app.FragmentTransaction;
  import android.util.TypedValue;
  import android.view.ContextThemeWrapper;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.Window;
  import android.view.accessibility.AccessibilityEvent;
  import android.widget.SpinnerAdapter;
  import com.actionbarsherlock.R;
  import com.actionbarsherlock.app.ActionBar;
  import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
  import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorListenerAdapter;
  import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet;
  import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
  import com.actionbarsherlock.internal.nineoldandroids.animation.Animator.AnimatorListener;
  import com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout;
  import com.actionbarsherlock.internal.view.menu.MenuBuilder;
  import com.actionbarsherlock.internal.view.menu.MenuPopupHelper;
  import com.actionbarsherlock.internal.view.menu.SubMenuBuilder;
  import com.actionbarsherlock.internal.widget.ActionBarContainer;
  import com.actionbarsherlock.internal.widget.ActionBarContextView;
  import com.actionbarsherlock.internal.widget.ActionBarView;
  import com.actionbarsherlock.internal.widget.ScrollingTabContainerView;
  import com.actionbarsherlock.view.ActionMode;
  import com.actionbarsherlock.view.Menu;
  import com.actionbarsherlock.view.MenuInflater;
  import com.actionbarsherlock.view.MenuItem;
  import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
  
  /**
   * ActionBarImpl is the ActionBar implementation used
   * by devices of all screen sizes. If it detects a compatible decor,
   * it will split contextual modes across both the ActionBarView at
   * the top of the screen and a horizontal LinearLayout at the bottom
   * which is normally hidden.
   */
  public class ActionBarImpl extends ActionBar {
      //UNUSED private static final String TAG = "ActionBarImpl";
  
      private Context mContext;
      private Context mThemedContext;
      private Activity mActivity;
      //UNUSED private Dialog mDialog;
  
      private ActionBarContainer mContainerView;
      private ActionBarView mActionView;
      private ActionBarContextView mContextView;
      private ActionBarContainer mSplitView;
      private NineFrameLayout mContentView;
      private ScrollingTabContainerView mTabScrollView;
  
      private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
  
      private TabImpl mSelectedTab;
      private int mSavedTabPosition = INVALID_POSITION;
  
      ActionModeImpl mActionMode;
      ActionMode mDeferredDestroyActionMode;
      ActionMode.Callback mDeferredModeDestroyCallback;
  
      private boolean mLastMenuVisibility;
      private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
              new ArrayList<OnMenuVisibilityListener>();
  
      private static final int CONTEXT_DISPLAY_NORMAL = 0;
      private static final int CONTEXT_DISPLAY_SPLIT = 1;
  
      private static final int INVALID_POSITION = -1;
  
      private int mContextDisplayMode;
      private boolean mHasEmbeddedTabs;
  
      final Handler mHandler = new Handler();
      Runnable mTabSelector;
  
      private Animator mCurrentShowAnim;
      private Animator mCurrentModeAnim;
      private boolean mShowHideAnimationEnabled;
      boolean mWasHiddenBeforeMode;
  
      final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
          @Override
          public void onAnimationEnd(Animator animation) {
              if (mContentView != null) {
                  mContentView.setTranslationY(0);
                  mContainerView.setTranslationY(0);
              }
              if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                  mSplitView.setVisibility(View.GONE);
              }
              mContainerView.setVisibility(View.GONE);
              mContainerView.setTransitioning(false);
              mCurrentShowAnim = null;
              completeDeferredDestroyActionMode();
          }
      };
  
      final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
          @Override
          public void onAnimationEnd(Animator animation) {
              mCurrentShowAnim = null;
              mContainerView.requestLayout();
          }
      };
  
      public ActionBarImpl(Activity activity, int features) {
          mActivity = activity;
          Window window = activity.getWindow();
          View decor = window.getDecorView();
          init(decor);
  
          //window.hasFeature() workaround for pre-3.0
          if ((features & (1 << Window.FEATURE_ACTION_BAR_OVERLAY)) == 0) {
              mContentView = (NineFrameLayout)decor.findViewById(android.R.id.content);
          }
      }
  
      public ActionBarImpl(Dialog dialog) {
          //UNUSED mDialog = dialog;
          init(dialog.getWindow().getDecorView());
      }
  
      private void init(View decor) {
          mContext = decor.getContext();
          mActionView = (ActionBarView) decor.findViewById(R.id.abs__action_bar);
          mContextView = (ActionBarContextView) decor.findViewById(
                  R.id.abs__action_context_bar);
          mContainerView = (ActionBarContainer) decor.findViewById(
                  R.id.abs__action_bar_container);
          mSplitView = (ActionBarContainer) decor.findViewById(
                  R.id.abs__split_action_bar);
  
          if (mActionView == null || mContextView == null || mContainerView == null) {
              throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
                      "with a compatible window decor layout");
          }
  
          mActionView.setContextView(mContextView);
          mContextDisplayMode = mActionView.isSplitActionBar() ?
                  CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
  
          // Older apps get the home button interaction enabled by default.
          // Newer apps need to enable it explicitly.
          boolean homeButtonEnabled = mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH;
  
          // If the homeAsUp display option is set, always enable the home button.
          homeButtonEnabled |= (mActionView.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0;
  
          setHomeButtonEnabled(homeButtonEnabled);
  
          setHasEmbeddedTabs(getResources_getBoolean(mContext,
                  R.bool.abs__action_bar_embed_tabs));
      }
  
      public void onConfigurationChanged(Configuration newConfig) {
          setHasEmbeddedTabs(getResources_getBoolean(mContext,
                  R.bool.abs__action_bar_embed_tabs));
  
          //Manually dispatch a configuration change to the action bar view on pre-2.2
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
              mActionView.onConfigurationChanged(newConfig);
              if (mContextView != null) {
                  mContextView.onConfigurationChanged(newConfig);
              }
          }
      }
  
      private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) {
          mHasEmbeddedTabs = hasEmbeddedTabs;
          // Switch tab layout configuration if needed
          if (!mHasEmbeddedTabs) {
              mActionView.setEmbeddedTabView(null);
              mContainerView.setTabContainer(mTabScrollView);
          } else {
              mContainerView.setTabContainer(null);
              mActionView.setEmbeddedTabView(mTabScrollView);
          }
          final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
          if (mTabScrollView != null) {
              mTabScrollView.setVisibility(isInTabMode ? View.VISIBLE : View.GONE);
          }
          mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
      }
  
      private void ensureTabsExist() {
          if (mTabScrollView != null) {
              return;
          }
  
          ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext);
  
          if (mHasEmbeddedTabs) {
              tabScroller.setVisibility(View.VISIBLE);
              mActionView.setEmbeddedTabView(tabScroller);
          } else {
              tabScroller.setVisibility(getNavigationMode() == NAVIGATION_MODE_TABS ?
                      View.VISIBLE : View.GONE);
              mContainerView.setTabContainer(tabScroller);
          }
          mTabScrollView = tabScroller;
      }
  
      void completeDeferredDestroyActionMode() {
          if (mDeferredModeDestroyCallback != null) {
              mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode);
              mDeferredDestroyActionMode = null;
              mDeferredModeDestroyCallback = null;
          }
      }
  
      /**
       * Enables or disables animation between show/hide states.
       * If animation is disabled using this method, animations in progress
       * will be finished.
       *
       * @param enabled true to animate, false to not animate.
       */
      public void setShowHideAnimationEnabled(boolean enabled) {
          mShowHideAnimationEnabled = enabled;
          if (!enabled && mCurrentShowAnim != null) {
              mCurrentShowAnim.end();
          }
      }
  
      public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
          mMenuVisibilityListeners.add(listener);
      }
  
      public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
          mMenuVisibilityListeners.remove(listener);
      }
  
      public void dispatchMenuVisibilityChanged(boolean isVisible) {
          if (isVisible == mLastMenuVisibility) {
              return;
          }
          mLastMenuVisibility = isVisible;
  
          final int count = mMenuVisibilityListeners.size();
          for (int i = 0; i < count; i++) {
              mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
          }
      }
  
      @Override
      public void setCustomView(int resId) {
          setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId, mActionView, false));
      }
  
      @Override
      public void setDisplayUseLogoEnabled(boolean useLogo) {
          setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
      }
  
      @Override
      public void setDisplayShowHomeEnabled(boolean showHome) {
          setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
      }
  
      @Override
      public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
          setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
      }
  
      @Override
      public void setDisplayShowTitleEnabled(boolean showTitle) {
          setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
      }
  
      @Override
      public void setDisplayShowCustomEnabled(boolean showCustom) {
          setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
      }
  
      @Override
      public void setHomeButtonEnabled(boolean enable) {
          mActionView.setHomeButtonEnabled(enable);
      }
  
      @Override
      public void setTitle(int resId) {
          setTitle(mContext.getString(resId));
      }
  
      @Override
      public void setSubtitle(int resId) {
          setSubtitle(mContext.getString(resId));
      }
  
      public void setSelectedNavigationItem(int position) {
          switch (mActionView.getNavigationMode()) {
          case NAVIGATION_MODE_TABS:
              selectTab(mTabs.get(position));
              break;
          case NAVIGATION_MODE_LIST:
              mActionView.setDropdownSelectedPosition(position);
              break;
          default:
              throw new IllegalStateException(
                      "setSelectedNavigationIndex not valid for current navigation mode");
          }
      }
  
      public void removeAllTabs() {
          cleanupTabs();
      }
  
      private void cleanupTabs() {
          if (mSelectedTab != null) {
              selectTab(null);
          }
          mTabs.clear();
          if (mTabScrollView != null) {
              mTabScrollView.removeAllTabs();
          }
          mSavedTabPosition = INVALID_POSITION;
      }
  
      public void setTitle(CharSequence title) {
          mActionView.setTitle(title);
      }
  
      public void setSubtitle(CharSequence subtitle) {
          mActionView.setSubtitle(subtitle);
      }
  
      public void setDisplayOptions(int options) {
          mActionView.setDisplayOptions(options);
      }
  
      public void setDisplayOptions(int options, int mask) {
          final int current = mActionView.getDisplayOptions();
          mActionView.setDisplayOptions((options & mask) | (current & ~mask));
      }
  
      public void setBackgroundDrawable(Drawable d) {
          mContainerView.setPrimaryBackground(d);
      }
  
      public void setStackedBackgroundDrawable(Drawable d) {
          mContainerView.setStackedBackground(d);
      }
  
      public void setSplitBackgroundDrawable(Drawable d) {
          if (mSplitView != null) {
              mSplitView.setSplitBackground(d);
          }
      }
  
      public View getCustomView() {
          return mActionView.getCustomNavigationView();
      }
  
      public CharSequence getTitle() {
          return mActionView.getTitle();
      }
  
      public CharSequence getSubtitle() {
          return mActionView.getSubtitle();
      }
  
      public int getNavigationMode() {
          return mActionView.getNavigationMode();
      }
  
      public int getDisplayOptions() {
          return mActionView.getDisplayOptions();
      }
  
      public ActionMode startActionMode(ActionMode.Callback callback) {
          boolean wasHidden = false;
          if (mActionMode != null) {
              wasHidden = mWasHiddenBeforeMode;
              mActionMode.finish();
          }
  
          mContextView.killMode();
          ActionModeImpl mode = new ActionModeImpl(callback);
          if (mode.dispatchOnCreate()) {
              mWasHiddenBeforeMode = !isShowing() || wasHidden;
              mode.invalidate();
              mContextView.initForMode(mode);
              animateToMode(true);
              if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                  // TODO animate this
                  mSplitView.setVisibility(View.VISIBLE);
              }
              mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
              mActionMode = mode;
              return mode;
          }
          return null;
      }
  
      private void configureTab(Tab tab, int position) {
          final TabImpl tabi = (TabImpl) tab;
          final ActionBar.TabListener callback = tabi.getCallback();
  
          if (callback == null) {
              throw new IllegalStateException("Action Bar Tab must have a Callback");
          }
  
          tabi.setPosition(position);
          mTabs.add(position, tabi);
  
          final int count = mTabs.size();
          for (int i = position + 1; i < count; i++) {
              mTabs.get(i).setPosition(i);
          }
      }
  
      @Override
      public void addTab(Tab tab) {
          addTab(tab, mTabs.isEmpty());
      }
  
      @Override
      public void addTab(Tab tab, int position) {
          addTab(tab, position, mTabs.isEmpty());
      }
  
      @Override
      public void addTab(Tab tab, boolean setSelected) {
          ensureTabsExist();
          mTabScrollView.addTab(tab, setSelected);
          configureTab(tab, mTabs.size());
          if (setSelected) {
              selectTab(tab);
          }
      }
  
      @Override
      public void addTab(Tab tab, int position, boolean setSelected) {
          ensureTabsExist();
          mTabScrollView.addTab(tab, position, setSelected);
          configureTab(tab, position);
          if (setSelected) {
              selectTab(tab);
          }
      }
  
      @Override
      public Tab newTab() {
          return new TabImpl();
      }
  
      @Override
      public void removeTab(Tab tab) {
          removeTabAt(tab.getPosition());
      }
  
      @Override
      public void removeTabAt(int position) {
          if (mTabScrollView == null) {
              // No tabs around to remove
              return;
          }
  
          int selectedTabPosition = mSelectedTab != null
                  ? mSelectedTab.getPosition() : mSavedTabPosition;
          mTabScrollView.removeTabAt(position);
          TabImpl removedTab = mTabs.remove(position);
          if (removedTab != null) {
              removedTab.setPosition(-1);
          }
  
          final int newTabCount = mTabs.size();
          for (int i = position; i < newTabCount; i++) {
              mTabs.get(i).setPosition(i);
          }
  
          if (selectedTabPosition == position) {
              selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
          }
      }
  
      @Override
      public void selectTab(Tab tab) {
          if (getNavigationMode() != NAVIGATION_MODE_TABS) {
              mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
              return;
          }
  
          FragmentTransaction trans = null;
          if (mActivity instanceof FragmentActivity) {
              trans = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
                      .disallowAddToBackStack();
          }
  
          if (mSelectedTab == tab) {
              if (mSelectedTab != null) {
                  mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
                  mTabScrollView.animateToTab(tab.getPosition());
              }
          } else {
              mTabScrollView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
              if (mSelectedTab != null) {
                  mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
              }
              mSelectedTab = (TabImpl) tab;
              if (mSelectedTab != null) {
                  mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
              }
          }
  
          if (trans != null && !trans.isEmpty()) {
              trans.commit();
          }
      }
  
      @Override
      public Tab getSelectedTab() {
          return mSelectedTab;
      }
  
      @Override
      public int getHeight() {
          return mContainerView.getHeight();
      }
  
      @Override
      public void show() {
          show(true);
      }
  
      void show(boolean markHiddenBeforeMode) {
          if (mCurrentShowAnim != null) {
              mCurrentShowAnim.end();
          }
          if (mContainerView.getVisibility() == View.VISIBLE) {
              if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
              return;
          }
          mContainerView.setVisibility(View.VISIBLE);
  
          if (mShowHideAnimationEnabled) {
              mContainerView.setAlpha(0);
              AnimatorSet anim = new AnimatorSet();
              AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1));
              if (mContentView != null) {
                  b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
                          -mContainerView.getHeight(), 0));
                  mContainerView.setTranslationY(-mContainerView.getHeight());
                  b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
              }
              if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
                  mSplitView.setAlpha(0);
                  mSplitView.setVisibility(View.VISIBLE);
                  b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1));
              }
              anim.addListener(mShowListener);
              mCurrentShowAnim = anim;
              anim.start();
          } else {
              mContainerView.setAlpha(1);
              mContainerView.setTranslationY(0);
              mShowListener.onAnimationEnd(null);
          }
      }
  
      @Override
      public void hide() {
          if (mCurrentShowAnim != null) {
              mCurrentShowAnim.end();
          }
          if (mContainerView.getVisibility() == View.GONE) {
              return;
          }
  
          if (mShowHideAnimationEnabled) {
              mContainerView.setAlpha(1);
              mContainerView.setTransitioning(true);
              AnimatorSet anim = new AnimatorSet();
              AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0));
              if (mContentView != null) {
                  b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
                          0, -mContainerView.getHeight()));
                  b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
                          -mContainerView.getHeight()));
              }
              if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
                  mSplitView.setAlpha(1);
                  b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0));
              }
              anim.addListener(mHideListener);
              mCurrentShowAnim = anim;
              anim.start();
          } else {
              mHideListener.onAnimationEnd(null);
          }
      }
  
      public boolean isShowing() {
          return mContainerView.getVisibility() == View.VISIBLE;
      }
  
      void animateToMode(boolean toActionMode) {
          if (toActionMode) {
              show(false);
          }
          if (mCurrentModeAnim != null) {
              mCurrentModeAnim.end();
          }
  
          mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
          mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
          if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) {
              mTabScrollView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
          }
      }
  
      public Context getThemedContext() {
          if (mThemedContext == null) {
              TypedValue outValue = new TypedValue();
              Resources.Theme currentTheme = mContext.getTheme();
              currentTheme.resolveAttribute(R.attr.actionBarWidgetTheme,
                      outValue, true);
              final int targetThemeRes = outValue.resourceId;
  
              if (targetThemeRes != 0) { //XXX && mContext.getThemeResId() != targetThemeRes) {
                  mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
              } else {
                  mThemedContext = mContext;
              }
          }
          return mThemedContext;
      }
  
      /**
       * @hide
       */
      public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
          private ActionMode.Callback mCallback;
          private MenuBuilder mMenu;
          private WeakReference<View> mCustomView;
  
          public ActionModeImpl(ActionMode.Callback callback) {
              mCallback = callback;
              mMenu = new MenuBuilder(getThemedContext())
                      .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
              mMenu.setCallback(this);
          }
  
          @Override
          public MenuInflater getMenuInflater() {
              return new MenuInflater(getThemedContext());
          }
  
          @Override
          public Menu getMenu() {
              return mMenu;
          }
  
          @Override
          public void finish() {
              if (mActionMode != this) {
                  // Not the active action mode - no-op
                  return;
              }
  
              // If we were hidden before the mode was shown, defer the onDestroy
              // callback until the animation is finished and associated relayout
              // is about to happen. This lets apps better anticipate visibility
              // and layout behavior.
              if (mWasHiddenBeforeMode) {
                  mDeferredDestroyActionMode = this;
                  mDeferredModeDestroyCallback = mCallback;
              } else {
                  mCallback.onDestroyActionMode(this);
              }
              mCallback = null;
              animateToMode(false);
  
              // Clear out the context mode views after the animation finishes
              mContextView.closeMode();
              mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
  
              mActionMode = null;
  
              if (mWasHiddenBeforeMode) {
                  hide();
              }
          }
  
          @Override
          public void invalidate() {
              mMenu.stopDispatchingItemsChanged();
              try {
                  mCallback.onPrepareActionMode(this, mMenu);
              } finally {
                  mMenu.startDispatchingItemsChanged();
              }
          }
  
          public boolean dispatchOnCreate() {
              mMenu.stopDispatchingItemsChanged();
              try {
                  return mCallback.onCreateActionMode(this, mMenu);
              } finally {
                  mMenu.startDispatchingItemsChanged();
              }
          }
  
          @Override
          public void setCustomView(View view) {
              mContextView.setCustomView(view);
              mCustomView = new WeakReference<View>(view);
          }
  
          @Override
          public void setSubtitle(CharSequence subtitle) {
              mContextView.setSubtitle(subtitle);
          }
  
          @Override
          public void setTitle(CharSequence title) {
              mContextView.setTitle(title);
          }
  
          @Override
          public void setTitle(int resId) {
              setTitle(mContext.getResources().getString(resId));
          }
  
          @Override
          public void setSubtitle(int resId) {
              setSubtitle(mContext.getResources().getString(resId));
          }
  
          @Override
          public CharSequence getTitle() {
              return mContextView.getTitle();
          }
  
          @Override
          public CharSequence getSubtitle() {
              return mContextView.getSubtitle();
          }
  
          @Override
          public View getCustomView() {
              return mCustomView != null ? mCustomView.get() : null;
          }
  
          public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
              if (mCallback != null) {
                  return mCallback.onActionItemClicked(this, item);
              } else {
                  return false;
              }
          }
  
          public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
          }
  
          public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
              if (mCallback == null) {
                  return false;
              }
  
              if (!subMenu.hasVisibleItems()) {
                  return true;
              }
  
              new MenuPopupHelper(getThemedContext(), subMenu).show();
              return true;
          }
  
          public void onCloseSubMenu(SubMenuBuilder menu) {
          }
  
          public void onMenuModeChange(MenuBuilder menu) {
              if (mCallback == null) {
                  return;
              }
              invalidate();
              mContextView.showOverflowMenu();
          }
      }
  
      /**
       * @hide
       */
      public class TabImpl extends ActionBar.Tab {
          private ActionBar.TabListener mCallback;
          private Object mTag;
          private Drawable mIcon;
          private CharSequence mText;
          private CharSequence mContentDesc;
          private int mPosition = -1;
          private View mCustomView;
  
          @Override
          public Object getTag() {
              return mTag;
          }
  
          @Override
          public Tab setTag(Object tag) {
              mTag = tag;
              return this;
          }
  
          public ActionBar.TabListener getCallback() {
              return mCallback;
          }
  
          @Override
          public Tab setTabListener(ActionBar.TabListener callback) {
              mCallback = callback;
              return this;
          }
  
          @Override
          public View getCustomView() {
              return mCustomView;
          }
  
          @Override
          public Tab setCustomView(View view) {
              mCustomView = view;
              if (mPosition >= 0) {
                  mTabScrollView.updateTab(mPosition);
              }
              return this;
          }
  
          @Override
          public Tab setCustomView(int layoutResId) {
              return setCustomView(LayoutInflater.from(getThemedContext())
                      .inflate(layoutResId, null));
          }
  
          @Override
          public Drawable getIcon() {
              return mIcon;
          }
  
          @Override
          public int getPosition() {
              return mPosition;
          }
  
          public void setPosition(int position) {
              mPosition = position;
          }
  
          @Override
          public CharSequence getText() {
              return mText;
          }
  
          @Override
          public Tab setIcon(Drawable icon) {
              mIcon = icon;
              if (mPosition >= 0) {
                  mTabScrollView.updateTab(mPosition);
              }
              return this;
          }
  
          @Override
          public Tab setIcon(int resId) {
              return setIcon(mContext.getResources().getDrawable(resId));
          }
  
          @Override
          public Tab setText(CharSequence text) {
              mText = text;
              if (mPosition >= 0) {
                  mTabScrollView.updateTab(mPosition);
              }
              return this;
          }
  
          @Override
          public Tab setText(int resId) {
              return setText(mContext.getResources().getText(resId));
          }
  
          @Override
          public void select() {
              selectTab(this);
          }
  
          @Override
          public Tab setContentDescription(int resId) {
              return setContentDescription(mContext.getResources().getText(resId));
          }
  
          @Override
          public Tab setContentDescription(CharSequence contentDesc) {
              mContentDesc = contentDesc;
              if (mPosition >= 0) {
                  mTabScrollView.updateTab(mPosition);
              }
              return this;
          }
  
          @Override
          public CharSequence getContentDescription() {
              return mContentDesc;
          }
      }
  
      @Override
      public void setCustomView(View view) {
          mActionView.setCustomNavigationView(view);
      }
  
      @Override
      public void setCustomView(View view, LayoutParams layoutParams) {
          view.setLayoutParams(layoutParams);
          mActionView.setCustomNavigationView(view);
      }
  
      @Override
      public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
          mActionView.setDropdownAdapter(adapter);
          mActionView.setCallback(callback);
      }
  
      @Override
      public int getSelectedNavigationIndex() {
          switch (mActionView.getNavigationMode()) {
              case NAVIGATION_MODE_TABS:
                  return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
              case NAVIGATION_MODE_LIST:
                  return mActionView.getDropdownSelectedPosition();
              default:
                  return -1;
          }
      }
  
      @Override
      public int getNavigationItemCount() {
          switch (mActionView.getNavigationMode()) {
              case NAVIGATION_MODE_TABS:
                  return mTabs.size();
              case NAVIGATION_MODE_LIST:
                  SpinnerAdapter adapter = mActionView.getDropdownAdapter();
                  return adapter != null ? adapter.getCount() : 0;
              default:
                  return 0;
          }
      }
  
      @Override
      public int getTabCount() {
          return mTabs.size();
      }
  
      @Override
      public void setNavigationMode(int mode) {
          final int oldMode = mActionView.getNavigationMode();
          switch (oldMode) {
              case NAVIGATION_MODE_TABS:
                  mSavedTabPosition = getSelectedNavigationIndex();
                  selectTab(null);
                  mTabScrollView.setVisibility(View.GONE);
                  break;
          }
          mActionView.setNavigationMode(mode);
          switch (mode) {
              case NAVIGATION_MODE_TABS:
                  ensureTabsExist();
                  mTabScrollView.setVisibility(View.VISIBLE);
                  if (mSavedTabPosition != INVALID_POSITION) {
                      setSelectedNavigationItem(mSavedTabPosition);
                      mSavedTabPosition = INVALID_POSITION;
                  }
                  break;
          }
          mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
      }
  
      @Override
      public Tab getTabAt(int index) {
          return mTabs.get(index);
      }
  
  
      @Override
      public void setIcon(int resId) {
          mActionView.setIcon(resId);
      }
  
      @Override
      public void setIcon(Drawable icon) {
          mActionView.setIcon(icon);
      }
  
      @Override
      public void setLogo(int resId) {
          mActionView.setLogo(resId);
      }
  
      @Override
      public void setLogo(Drawable logo) {
          mActionView.setLogo(logo);
      }
  }
  