aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarImpl.java')
-rw-r--r--libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarImpl.java1026
1 files changed, 1026 insertions, 0 deletions
diff --git a/libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarImpl.java b/libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarImpl.java
new file mode 100644
index 000000000..d022a2465
--- /dev/null
+++ b/libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarImpl.java
@@ -0,0 +1,1026 @@
+/*
+ * 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.
+ setHomeButtonEnabled(mContext.getApplicationInfo().targetSdkVersion < 14);
+
+ 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);
+ }
+}