1027 lines
32 KiB
Java
1027 lines
32 KiB
Java
/*
|
|
* 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.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.app.SherlockFragmentActivity;
|
|
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 SherlockFragmentActivity) {
|
|
trans = ((SherlockFragmentActivity)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);
|
|
}
|
|
}
|