Skip to content

Instantly share code, notes, and snippets.

@mburumaxwell
Created January 4, 2014 11:18
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save mburumaxwell/8254359 to your computer and use it in GitHub Desktop.
Save mburumaxwell/8254359 to your computer and use it in GitHub Desktop.
Implementing PreferenceActivity using ActionBarCompat. Add all these files to your project in a package name: android.support.v7.app In your PreferenceActivity extend ActionBarPreferenceActivity If you haven't started using ActionBarCompat and need to implement a PreferenceActivity, I advice you use ActionBarSherlock
package android.support.v7.app;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v7.app.ActionBar;
import android.support.v7.internal.view.SupportMenuInflater;
import android.support.v7.view.ActionMode;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
public abstract class ActionBarActivityDelegateCompat {
static final String METADATA_UI_OPTIONS = "android.support.UI_OPTIONS";
static final String UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = "splitActionBarWhenNarrow";
private static final String TAG = "ActionBarActivityDelegate";
static ActionBarActivityDelegateCompat createDelegate(ActionBarPreferenceActivity activity) {
final int version = Build.VERSION.SDK_INT;
if (version >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return new ActionBarActivityDelegateCompatICS(activity);
} else if (version >= Build.VERSION_CODES.HONEYCOMB) {
return new ActionBarActivityDelegateCompatHC(activity);
} else {
return new ActionBarActivityDelegateCompatBase(activity);
}
}
final ActionBarPreferenceActivity mActivity;
private ActionBar mActionBar;
private MenuInflater mMenuInflater;
// true if this activity has an action bar.
boolean mHasActionBar;
// true if this activity's action bar overlays other activity content.
boolean mOverlayActionBar;
ActionBarActivityDelegateCompat(ActionBarPreferenceActivity activity) {
mActivity = activity;
}
abstract ActionBar createSupportActionBar();
final ActionBar getSupportActionBar() {
// The Action Bar should be lazily created as mHasActionBar or mOverlayActionBar
// could change after onCreate
if (mHasActionBar || mOverlayActionBar) {
if (mActionBar == null) {
mActionBar = createSupportActionBar();
}
} else {
// If we're not set to have a Action Bar, null it just in case it's been set
mActionBar = null;
}
return mActionBar;
}
MenuInflater getMenuInflater() {
if (mMenuInflater == null) {
ActionBar ab = getSupportActionBar();
if (ab != null) {
mMenuInflater = new SupportMenuInflater(ab.getThemedContext());
} else {
mMenuInflater = new SupportMenuInflater(mActivity);
}
}
return mMenuInflater;
}
void onCreate(Bundle savedInstanceState) {
TypedArray a = mActivity.obtainStyledAttributes(R.styleable.ActionBarWindow);
if (!a.hasValue(R.styleable.ActionBarWindow_windowActionBar)) {
a.recycle();
throw new IllegalStateException(
"You need to use a Theme.AppCompat theme (or descendant) with this activity.");
}
mHasActionBar = a.getBoolean(R.styleable.ActionBarWindow_windowActionBar, false);
mOverlayActionBar = a.getBoolean(R.styleable.ActionBarWindow_windowActionBarOverlay, false);
a.recycle();
}
abstract void onConfigurationChanged(Configuration newConfig);
abstract void onStop();
abstract void onPostResume();
abstract void setContentView(View v);
abstract void setContentView(int resId);
abstract void setContentView(View v, ViewGroup.LayoutParams lp);
abstract void addContentView(View v, ViewGroup.LayoutParams lp);
abstract void setTitle(CharSequence title);
abstract void supportInvalidateOptionsMenu();
abstract boolean supportRequestWindowFeature(int featureId);
// Methods used to create and respond to options menu
abstract View onCreatePanelView(int featureId);
abstract boolean onPreparePanel(int featureId, View view, Menu menu);
abstract boolean onCreatePanelMenu(int featureId, Menu menu);
abstract boolean onMenuItemSelected(int featureId, MenuItem item);
abstract boolean onBackPressed();
abstract ActionMode startSupportActionMode(ActionMode.Callback callback);
abstract void setSupportProgressBarVisibility(boolean visible);
abstract void setSupportProgressBarIndeterminateVisibility(boolean visible);
abstract void setSupportProgressBarIndeterminate(boolean indeterminate);
abstract void setSupportProgress(int progress);
abstract ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
protected final String getUiOptionsFromMetadata() {
try {
PackageManager pm = mActivity.getPackageManager();
ActivityInfo info = pm.getActivityInfo(mActivity.getComponentName(),
PackageManager.GET_META_DATA);
String uiOptions = null;
if (info.metaData != null) {
uiOptions = info.metaData.getString(METADATA_UI_OPTIONS);
}
return uiOptions;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "getUiOptionsFromMetadata: Activity '" + mActivity.getClass()
.getSimpleName() + "' not in manifest");
return null;
}
}
protected final Context getActionBarThemedContext() {
Context context = mActivity;
// If we have an action bar, initialize the menu with a context themed from it.
ActionBar ab = getSupportActionBar();
if (ab != null) {
context = ab.getThemedContext();
}
return context;
}
}
package android.support.v7.app;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.WindowCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.internal.view.menu.ListMenuPresenter;
import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.internal.view.menu.MenuPresenter;
import android.support.v7.internal.view.menu.MenuView;
import android.support.v7.internal.view.menu.MenuWrapperFactory;
import android.support.v7.internal.widget.ActionBarContainer;
import android.support.v7.internal.widget.ActionBarContextView;
import android.support.v7.internal.widget.ActionBarView;
import android.support.v7.internal.widget.ProgressBarICS;
import android.support.v7.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;
public class ActionBarActivityDelegateCompatBase extends ActionBarActivityDelegateCompat implements
MenuPresenter.Callback, MenuBuilder.Callback {
@SuppressWarnings("unused")
private static final String TAG = "ActionBarActivityDelegateBase";
private static final int[] ACTION_BAR_DRAWABLE_TOGGLE_ATTRS = new int[] {
R.attr.homeAsUpIndicator
};
private ActionBarView mActionBarView;
private ListMenuPresenter mListMenuPresenter;
private MenuBuilder mMenu;
private ActionMode mActionMode;
// true if we have installed a window sub-decor layout.
private boolean mSubDecorInstalled;
// Used to keep track of Progress Bar Window features
private boolean mFeatureProgress, mFeatureIndeterminateProgress;
private boolean mInvalidateMenuPosted;
private final Runnable mInvalidateMenuRunnable = new Runnable() {
@Override
public void run() {
final MenuBuilder menu = createMenu();
if (mActivity.superOnCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu) &&
mActivity.superOnPreparePanel(Window.FEATURE_OPTIONS_PANEL, null, menu)) {
setMenu(menu);
} else {
setMenu(null);
}
mInvalidateMenuPosted = false;
}
};
ActionBarActivityDelegateCompatBase(ActionBarPreferenceActivity activity) {
super(activity);
}
@Override
public ActionBar createSupportActionBar() {
ensureSubDecor();
return new ActionBarImplCompatBase(mActivity, mActivity);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
// If this is called before sub-decor is installed, ActionBar will not
// be properly initialized.
if (mHasActionBar && mSubDecorInstalled) {
// Note: The action bar will need to access
// view changes from superclass.
ActionBarImplCompatBase actionBar = (ActionBarImplCompatBase) getSupportActionBar();
actionBar.onConfigurationChanged(newConfig);
}
}
@Override
public void onStop() {
ActionBarImplCompatBase ab = (ActionBarImplCompatBase) getSupportActionBar();
if (ab != null) {
ab.setShowHideAnimationEnabled(false);
}
}
@Override
public void onPostResume() {
ActionBarImplCompatBase ab = (ActionBarImplCompatBase) getSupportActionBar();
if (ab != null) {
ab.setShowHideAnimationEnabled(true);
}
}
@Override
public void setContentView(View v) {
ensureSubDecor();
if (mHasActionBar) {
final ViewGroup contentParent =
(ViewGroup) mActivity.findViewById(R.id.action_bar_activity_content);
contentParent.removeAllViews();
contentParent.addView(v);
} else {
mActivity.superSetContentView(v);
}
}
@Override
public void setContentView(int resId) {
ensureSubDecor();
if (mHasActionBar) {
final ViewGroup contentParent =
(ViewGroup) mActivity.findViewById(R.id.action_bar_activity_content);
contentParent.removeAllViews();
final LayoutInflater inflater = mActivity.getLayoutInflater();
inflater.inflate(resId, contentParent);
} else {
mActivity.superSetContentView(resId);
}
}
@Override
public void setContentView(View v, ViewGroup.LayoutParams lp) {
ensureSubDecor();
if (mHasActionBar) {
final ViewGroup contentParent =
(ViewGroup) mActivity.findViewById(R.id.action_bar_activity_content);
contentParent.removeAllViews();
contentParent.addView(v, lp);
} else {
mActivity.superSetContentView(v, lp);
}
}
@Override
public void addContentView(View v, ViewGroup.LayoutParams lp) {
ensureSubDecor();
if (mHasActionBar) {
final ViewGroup contentParent =
(ViewGroup) mActivity.findViewById(R.id.action_bar_activity_content);
contentParent.addView(v, lp);
} else {
mActivity.superSetContentView(v, lp);
}
}
final void ensureSubDecor() {
if (mHasActionBar && !mSubDecorInstalled) {
if (mOverlayActionBar) {
mActivity.superSetContentView(R.layout.abc_action_bar_decor_overlay);
} else {
mActivity.superSetContentView(R.layout.abc_action_bar_decor);
}
mActionBarView = (ActionBarView) mActivity.findViewById(R.id.action_bar);
mActionBarView.setWindowCallback(mActivity);
/**
* Progress Bars
*/
if (mFeatureProgress) {
mActionBarView.initProgress();
}
if (mFeatureIndeterminateProgress) {
mActionBarView.initIndeterminateProgress();
}
/**
* Split Action Bar
*/
boolean splitWhenNarrow = UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW
.equals(getUiOptionsFromMetadata());
boolean splitActionBar;
if (splitWhenNarrow) {
splitActionBar = mActivity.getResources()
.getBoolean(R.bool.abc_split_action_bar_is_narrow);
} else {
TypedArray a = mActivity.obtainStyledAttributes(R.styleable.ActionBarWindow);
splitActionBar = a
.getBoolean(R.styleable.ActionBarWindow_windowSplitActionBar, false);
a.recycle();
}
final ActionBarContainer splitView = (ActionBarContainer) mActivity.findViewById(
R.id.split_action_bar);
if (splitView != null) {
mActionBarView.setSplitView(splitView);
mActionBarView.setSplitActionBar(splitActionBar);
mActionBarView.setSplitWhenNarrow(splitWhenNarrow);
final ActionBarContextView cab = (ActionBarContextView) mActivity.findViewById(
R.id.action_context_bar);
cab.setSplitView(splitView);
cab.setSplitActionBar(splitActionBar);
cab.setSplitWhenNarrow(splitWhenNarrow);
}
mSubDecorInstalled = true;
supportInvalidateOptionsMenu();
}
}
@Override
public boolean supportRequestWindowFeature(int featureId) {
switch (featureId) {
case WindowCompat.FEATURE_ACTION_BAR:
mHasActionBar = true;
return true;
case WindowCompat.FEATURE_ACTION_BAR_OVERLAY:
mOverlayActionBar = true;
return true;
case Window.FEATURE_PROGRESS:
mFeatureProgress = true;
return true;
case Window.FEATURE_INDETERMINATE_PROGRESS:
mFeatureIndeterminateProgress = true;
return true;
default:
return mActivity.requestWindowFeature(featureId);
}
}
@Override
public void setTitle(CharSequence title) {
ActionBar ab = getSupportActionBar();
if (ab != null) {
ab.setTitle(title);
}
}
@Override
public View onCreatePanelView(int featureId) {
View createdPanelView = null;
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
boolean show = true;
MenuBuilder menu = mMenu;
if (mActionMode == null) {
// We only want to dispatch Activity/Fragment menu calls if there isn't
// currently an action mode
if (menu == null) {
// We don't have a menu created, so create one
menu = createMenu();
setMenu(menu);
// Make sure we're not dispatching item changes to presenters
menu.stopDispatchingItemsChanged();
// Dispatch onCreateSupportOptionsMenu
show = mActivity.superOnCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu);
}
if (show) {
// Make sure we're not dispatching item changes to presenters
menu.stopDispatchingItemsChanged();
// Dispatch onPrepareSupportOptionsMenu
show = mActivity.superOnPreparePanel(Window.FEATURE_OPTIONS_PANEL, null, menu);
}
}
if (show) {
createdPanelView = (View) getListMenuView(mActivity, this);
// Allow menu to start dispatching changes to presenters
menu.startDispatchingItemsChanged();
} else {
// If the menu isn't being shown, we no longer need it
setMenu(null);
}
}
return createdPanelView;
}
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
if (featureId != Window.FEATURE_OPTIONS_PANEL) {
return mActivity.superOnCreatePanelMenu(featureId, menu);
}
return false;
}
@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
if (featureId != Window.FEATURE_OPTIONS_PANEL) {
return mActivity.superOnPreparePanel(featureId, view, menu);
}
return false;
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
item = MenuWrapperFactory.createMenuItemWrapper(item);
}
return mActivity.superOnMenuItemSelected(featureId, item);
}
@Override
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
return mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);
}
@Override
public void onMenuModeChange(MenuBuilder menu) {
reopenMenu(menu, true);
}
@Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
mActivity.closeOptionsMenu();
}
@Override
public boolean onOpenSubMenu(MenuBuilder subMenu) {
return false;
}
@Override
public ActionMode startSupportActionMode(ActionMode.Callback callback) {
if (callback == null) {
throw new IllegalArgumentException("ActionMode callback can not be null.");
}
if (mActionMode != null) {
mActionMode.finish();
}
final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
ActionBarImplCompatBase ab = (ActionBarImplCompatBase) getSupportActionBar();
if (ab != null) {
mActionMode = ab.startActionMode(wrappedCallback);
}
if (mActionMode != null) {
mActivity.onSupportActionModeStarted(mActionMode);
}
return mActionMode;
}
@Override
public void supportInvalidateOptionsMenu() {
if (!mInvalidateMenuPosted) {
mInvalidateMenuPosted = true;
mActivity.getWindow().getDecorView().post(mInvalidateMenuRunnable);
}
}
private MenuBuilder createMenu() {
MenuBuilder menu = new MenuBuilder(getActionBarThemedContext());
menu.setCallback(this);
return menu;
}
private void reopenMenu(MenuBuilder menu, boolean toggleMenuMode) {
if (mActionBarView != null && mActionBarView.isOverflowReserved()) {
if (!mActionBarView.isOverflowMenuShowing() || !toggleMenuMode) {
if (mActionBarView.getVisibility() == View.VISIBLE) {
mActionBarView.showOverflowMenu();
}
} else {
mActionBarView.hideOverflowMenu();
}
return;
}
menu.close();
}
private MenuView getListMenuView(Context context, MenuPresenter.Callback cb) {
if (mMenu == null) {
return null;
}
if (mListMenuPresenter == null) {
TypedArray a = context.obtainStyledAttributes(R.styleable.Theme);
final int listPresenterTheme = a.getResourceId(
R.styleable.Theme_panelMenuListTheme,
R.style.Theme_AppCompat_CompactMenu);
a.recycle();
mListMenuPresenter = new ListMenuPresenter(
R.layout.abc_list_menu_item_layout, listPresenterTheme);
mListMenuPresenter.setCallback(cb);
mMenu.addMenuPresenter(mListMenuPresenter);
} else {
// Make sure we update the ListView
mListMenuPresenter.updateMenuView(false);
}
return mListMenuPresenter.getMenuView(new FrameLayout(context));
}
private void setMenu(MenuBuilder menu) {
if (menu == mMenu) {
return;
}
if (mMenu != null) {
mMenu.removeMenuPresenter(mListMenuPresenter);
}
mMenu = menu;
if (menu != null && mListMenuPresenter != null) {
// Only update list menu if there isn't an action mode menu
menu.addMenuPresenter(mListMenuPresenter);
}
if (mActionBarView != null) {
mActionBarView.setMenu(menu, this);
}
}
@Override
public boolean onBackPressed() {
// Back cancels action modes first.
if (mActionMode != null) {
mActionMode.finish();
return true;
}
// Next collapse any expanded action views.
if (mActionBarView != null && mActionBarView.hasExpandedActionView()) {
mActionBarView.collapseActionView();
return true;
}
return false;
}
@Override
void setSupportProgressBarVisibility(boolean visible) {
updateProgressBars(visible ? Window.PROGRESS_VISIBILITY_ON :
Window.PROGRESS_VISIBILITY_OFF);
}
@Override
void setSupportProgressBarIndeterminateVisibility(boolean visible) {
updateProgressBars(visible ? Window.PROGRESS_VISIBILITY_ON :
Window.PROGRESS_VISIBILITY_OFF);
}
@Override
void setSupportProgressBarIndeterminate(boolean indeterminate) {
updateProgressBars(indeterminate ? Window.PROGRESS_INDETERMINATE_ON
: Window.PROGRESS_INDETERMINATE_OFF);
}
@Override
void setSupportProgress(int progress) {
updateProgressBars(Window.PROGRESS_START + progress);
}
@Override
ActionBarDrawerToggle.Delegate getDrawerToggleDelegate() {
return new ActionBarDrawableToggleImpl();
}
/**
* Progress Bar function. Mostly extracted from PhoneWindow.java
*/
private void updateProgressBars(int value) {
ProgressBarICS circularProgressBar = getCircularProgressBar();
ProgressBarICS horizontalProgressBar = getHorizontalProgressBar();
if (value == Window.PROGRESS_VISIBILITY_ON) {
if (mFeatureProgress) {
int level = horizontalProgressBar.getProgress();
int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ?
View.VISIBLE : View.INVISIBLE;
horizontalProgressBar.setVisibility(visibility);
}
if (mFeatureIndeterminateProgress) {
circularProgressBar.setVisibility(View.VISIBLE);
}
} else if (value == Window.PROGRESS_VISIBILITY_OFF) {
if (mFeatureProgress) {
horizontalProgressBar.setVisibility(View.GONE);
}
if (mFeatureIndeterminateProgress) {
circularProgressBar.setVisibility(View.GONE);
}
} else if (value == Window.PROGRESS_INDETERMINATE_ON) {
horizontalProgressBar.setIndeterminate(true);
} else if (value == Window.PROGRESS_INDETERMINATE_OFF) {
horizontalProgressBar.setIndeterminate(false);
} else if (Window.PROGRESS_START <= value && value <= Window.PROGRESS_END) {
// We want to set the progress value before testing for visibility
// so that when the progress bar becomes visible again, it has the
// correct level.
horizontalProgressBar.setProgress(value - Window.PROGRESS_START);
if (value < Window.PROGRESS_END) {
showProgressBars(horizontalProgressBar, circularProgressBar);
} else {
hideProgressBars(horizontalProgressBar, circularProgressBar);
}
}
}
private void showProgressBars(ProgressBarICS horizontalProgressBar,
ProgressBarICS spinnyProgressBar) {
if (mFeatureIndeterminateProgress && spinnyProgressBar.getVisibility() == View.INVISIBLE) {
spinnyProgressBar.setVisibility(View.VISIBLE);
}
// Only show the progress bars if the primary progress is not complete
if (mFeatureProgress && horizontalProgressBar.getProgress() < 10000) {
horizontalProgressBar.setVisibility(View.VISIBLE);
}
}
private void hideProgressBars(ProgressBarICS horizontalProgressBar,
ProgressBarICS spinnyProgressBar) {
if (mFeatureIndeterminateProgress && spinnyProgressBar.getVisibility() == View.VISIBLE) {
spinnyProgressBar.setVisibility(View.INVISIBLE);
}
if (mFeatureProgress && horizontalProgressBar.getVisibility() == View.VISIBLE) {
horizontalProgressBar.setVisibility(View.INVISIBLE);
}
}
private ProgressBarICS getCircularProgressBar() {
ProgressBarICS pb = (ProgressBarICS) mActionBarView.findViewById(R.id.progress_circular);
if (pb != null) {
pb.setVisibility(View.INVISIBLE);
}
return pb;
}
private ProgressBarICS getHorizontalProgressBar() {
ProgressBarICS pb = (ProgressBarICS) mActionBarView.findViewById(R.id.progress_horizontal);
if (pb != null) {
pb.setVisibility(View.INVISIBLE);
}
return pb;
}
/**
* Clears out internal reference when the action mode is destroyed.
*/
private class ActionModeCallbackWrapper implements ActionMode.Callback {
private ActionMode.Callback mWrapped;
public ActionModeCallbackWrapper(ActionMode.Callback wrapped) {
mWrapped = wrapped;
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return mWrapped.onCreateActionMode(mode, menu);
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return mWrapped.onPrepareActionMode(mode, menu);
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return mWrapped.onActionItemClicked(mode, item);
}
public void onDestroyActionMode(ActionMode mode) {
mWrapped.onDestroyActionMode(mode);
mActivity.onSupportActionModeFinished(mode);
mActionMode = null;
}
}
private class ActionBarDrawableToggleImpl
implements ActionBarDrawerToggle.Delegate {
@Override
public Drawable getThemeUpIndicator() {
final TypedArray a = mActivity.obtainStyledAttributes(ACTION_BAR_DRAWABLE_TOGGLE_ATTRS);
final Drawable result = a.getDrawable(0);
a.recycle();
return result;
}
@Override
public void setActionBarUpIndicator(Drawable upDrawable, int contentDescRes) {
if (mActionBarView != null) {
mActionBarView.setHomeAsUpIndicator(upDrawable);
}
}
@Override
public void setActionBarDescription(int contentDescRes) {
// No support for setting Action Bar content description
}
}
}
package android.support.v7.app;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.view.Window;
class ActionBarActivityDelegateCompatHC extends ActionBarActivityDelegateCompatBase {
ActionBarActivityDelegateCompatHC(ActionBarPreferenceActivity activity) {
super(activity);
}
@Override
void onCreate(Bundle savedInstanceState) {
/**
* A native Action Mode could be displayed (text selection, etc) so we need to make sure it
* is positioned correctly. Here we request the ACTION_MODE_OVERLAY feature so that it
* displays over the compat Action Bar.
* {@link android.support.v7.internal.widget.NativeActionModeAwareLayout} is responsible for
* making sure that the compat Action Bar is visible when an Action Mode is started
* (for positioning).
*/
mActivity.getWindow().requestFeature(Window.FEATURE_ACTION_MODE_OVERLAY);
super.onCreate(savedInstanceState);
}
@Override
public ActionBar createSupportActionBar() {
ensureSubDecor();
return new ActionBarImplCompatHC(mActivity, mActivity);
}
}
package android.support.v7.app;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.WindowCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.internal.view.ActionModeWrapper;
import android.support.v7.internal.view.menu.MenuWrapperFactory;
import android.support.v7.view.ActionMode;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
class ActionBarActivityDelegateCompatICS extends ActionBarActivityDelegateCompat {
Menu mMenu;
ActionBarActivityDelegateCompatICS(ActionBarPreferenceActivity activity) {
super(activity);
}
@Override
public ActionBar createSupportActionBar() {
return new ActionBarImplCompatICS(mActivity, mActivity);
}
@Override
public void onCreate(Bundle savedInstanceState) {
// Set framework uiOptions from the support metadata value
if (UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW.equals(getUiOptionsFromMetadata())) {
mActivity.getWindow().setUiOptions(ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW,
ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);
}
if (mHasActionBar) {
// If action bar is requested by inheriting from the appcompat theme,
// the system will not know about that. So explicitly request for an action bar.
mActivity.requestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
}
if (mOverlayActionBar) {
mActivity.requestWindowFeature(WindowCompat.FEATURE_ACTION_BAR_OVERLAY);
}
super.onCreate(savedInstanceState);
/*
* This goofy move needs some explanation.
*
* The verifier on older platform versions has some interesting side effects if
* a class defines a method that takes a parameter of a type that doesn't exist.
* In this case, that type is android.view.ActionMode. Therefore, ActionBarActivity
* cannot override the onActionModeStarted/Finished methods without causing nastiness
* when it is loaded on older platform versions.
*
* Since these methods are actually part of the window callback and not intrinsic to
* Activity itself, we can install a little shim with the window instead that knows
* about the ActionMode class. Note that this means that any new methods added to
* Window.Callback in the future won't get proxied without updating the support lib,
* but we shouldn't be adding new methods to public interfaces that way anyway...right? ;)
*/
final Window w = mActivity.getWindow();
w.setCallback(createWindowCallbackWrapper(w.getCallback()));
}
Window.Callback createWindowCallbackWrapper(Window.Callback cb) {
return new WindowCallbackWrapper(cb);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
}
@Override
public void onStop() {
}
@Override
public void onPostResume() {
}
@Override
public void setContentView(View v) {
mActivity.superSetContentView(v);
}
@Override
public void setContentView(int resId) {
mActivity.superSetContentView(resId);
}
@Override
public void setContentView(View v, ViewGroup.LayoutParams lp) {
mActivity.superSetContentView(v, lp);
}
@Override
public void addContentView(View v, ViewGroup.LayoutParams lp) {
mActivity.superAddContentView(v, lp);
}
@Override
public boolean supportRequestWindowFeature(int featureId) {
return mActivity.requestWindowFeature(featureId);
}
@Override
public View onCreatePanelView(int featureId) {
// Do not create custom options menu on HC+
return null;
}
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
if (featureId == Window.FEATURE_OPTIONS_PANEL || featureId == Window.FEATURE_ACTION_BAR) {
if (mMenu == null) {
mMenu = MenuWrapperFactory.createMenuWrapper(menu);
}
return mActivity.superOnCreatePanelMenu(featureId, mMenu);
}
return mActivity.superOnCreatePanelMenu(featureId, menu);
}
@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
if (featureId == Window.FEATURE_OPTIONS_PANEL || featureId == Window.FEATURE_ACTION_BAR) {
return mActivity.superOnPreparePanel(featureId, view, mMenu);
}
return mActivity.superOnPreparePanel(featureId, view, menu);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
item = MenuWrapperFactory.createMenuItemWrapper(item);
}
return mActivity.superOnMenuItemSelected(featureId, item);
}
@Override
public void setTitle(CharSequence title) {
// Handled by framework
}
@Override
public ActionMode startSupportActionMode(ActionMode.Callback callback) {
if (callback == null) {
throw new IllegalArgumentException("ActionMode callback can not be null.");
}
Context context = getActionBarThemedContext();
ActionModeWrapper.CallbackWrapper wrappedCallback = new ActionModeWrapper.CallbackWrapper(
context, callback);
ActionModeWrapper wrappedMode = null;
android.view.ActionMode frameworkMode = mActivity.startActionMode(wrappedCallback);
if (frameworkMode != null) {
wrappedMode = new ActionModeWrapper(context,
mActivity.startActionMode(wrappedCallback));
wrappedCallback.setLastStartedActionMode(wrappedMode);
}
return wrappedMode;
}
public void onActionModeStarted(android.view.ActionMode mode) {
mActivity.onSupportActionModeStarted(
new ActionModeWrapper(getActionBarThemedContext(), mode));
}
@Override
void setSupportProgressBarVisibility(boolean visible) {
mActivity.setProgressBarVisibility(visible);
}
@Override
void setSupportProgressBarIndeterminateVisibility(boolean visible) {
mActivity.setProgressBarIndeterminateVisibility(visible);
}
@Override
void setSupportProgressBarIndeterminate(boolean indeterminate) {
mActivity.setProgressBarIndeterminate(indeterminate);
}
@Override
void setSupportProgress(int progress) {
mActivity.setProgress(progress);
}
public void onActionModeFinished(android.view.ActionMode mode) {
mActivity.onSupportActionModeFinished(
new ActionModeWrapper(getActionBarThemedContext(), mode));
}
@Override
public void supportInvalidateOptionsMenu() {
mMenu = null;
}
@Override
public boolean onBackPressed() {
return false;
}
@Override
public ActionBarDrawerToggle.Delegate getDrawerToggleDelegate() {
// Return null so that ActionBarDrawableToggle uses it's standard impl
return null;
}
class WindowCallbackWrapper implements Window.Callback {
final Window.Callback mWrapped;
public WindowCallbackWrapper(Window.Callback wrapped) {
mWrapped = wrapped;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
return mWrapped.dispatchKeyEvent(event);
}
@Override
public boolean dispatchKeyShortcutEvent(KeyEvent event) {
return mWrapped.dispatchKeyShortcutEvent(event);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return mWrapped.dispatchTouchEvent(event);
}
@Override
public boolean dispatchTrackballEvent(MotionEvent event) {
return mWrapped.dispatchTrackballEvent(event);
}
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
return mWrapped.dispatchGenericMotionEvent(event);
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
return mWrapped.dispatchPopulateAccessibilityEvent(event);
}
@Override
public View onCreatePanelView(int featureId) {
return mWrapped.onCreatePanelView(featureId);
}
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
return mWrapped.onCreatePanelMenu(featureId, menu);
}
@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
return mWrapped.onPreparePanel(featureId, view, menu);
}
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
return mWrapped.onMenuOpened(featureId, menu);
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
return mWrapped.onMenuItemSelected(featureId, item);
}
@Override
public void onWindowAttributesChanged(WindowManager.LayoutParams attrs) {
mWrapped.onWindowAttributesChanged(attrs);
}
@Override
public void onContentChanged() {
mWrapped.onContentChanged();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
mWrapped.onWindowFocusChanged(hasFocus);
}
@Override
public void onAttachedToWindow() {
mWrapped.onAttachedToWindow();
}
@Override
public void onDetachedFromWindow() {
mWrapped.onDetachedFromWindow();
}
@Override
public void onPanelClosed(int featureId, Menu menu) {
mWrapped.onPanelClosed(featureId, menu);
}
@Override
public boolean onSearchRequested() {
return mWrapped.onSearchRequested();
}
@Override
public android.view.ActionMode onWindowStartingActionMode(
android.view.ActionMode.Callback callback) {
return mWrapped.onWindowStartingActionMode(callback);
}
/*
* And here are the money methods, the reason why this wrapper exists:
*/
@Override
public void onActionModeStarted(android.view.ActionMode mode) {
mWrapped.onActionModeStarted(mode);
ActionBarActivityDelegateCompatICS.this.onActionModeStarted(mode);
}
@Override
public void onActionModeFinished(android.view.ActionMode mode) {
mWrapped.onActionModeFinished(mode);
ActionBarActivityDelegateCompatICS.this.onActionModeFinished(mode);
}
}
}
/*
* Copyright (C) 2012 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 android.support.v7.app;
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.Handler;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.internal.view.ActionBarPolicy;
import android.support.v7.internal.view.SupportMenuInflater;
import android.support.v7.internal.view.menu.MenuBuilder;
import android.support.v7.internal.view.menu.SubMenuBuilder;
import android.support.v7.internal.widget.ActionBarContainer;
import android.support.v7.internal.widget.ActionBarContextView;
import android.support.v7.internal.widget.ActionBarOverlayLayout;
import android.support.v7.internal.widget.ActionBarView;
import android.support.v7.internal.widget.ScrollingTabContainerView;
import android.support.v7.view.ActionMode;
import android.support.v4.internal.view.SupportMenuItem;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.SpinnerAdapter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@SuppressWarnings("unused")
class ActionBarImplCompatBase extends ActionBar {
private Context mContext;
private Context mThemedContext;
private ActionBarPreferenceActivity mActivity;
private Dialog mDialog;
private ActionBarOverlayLayout mOverlayLayout;
private ActionBarContainer mContainerView;
private ViewGroup mTopVisibilityView;
private ActionBarView mActionView;
private ActionBarContextView mContextView;
private ActionBarContainer mSplitView;
private View mContentView;
private ScrollingTabContainerView mTabScrollView;
private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
private TabImpl mSelectedTab;
private int mSavedTabPosition = INVALID_POSITION;
private boolean mDisplayHomeAsUpSet;
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 int mCurWindowVisibility = View.VISIBLE;
private boolean mHiddenByApp;
private boolean mHiddenBySystem;
private boolean mShowingForMode;
private boolean mNowShowing = true;
private boolean mShowHideAnimationEnabled;
private Callback mCallback;
public ActionBarImplCompatBase(ActionBarPreferenceActivity activity, Callback callback) {
mActivity = activity;
mContext = activity;
mCallback = callback;
init(mActivity);
}
private void init(ActionBarPreferenceActivity activity) {
mOverlayLayout = (ActionBarOverlayLayout) activity.findViewById(
R.id.action_bar_overlay_layout);
if (mOverlayLayout != null) {
mOverlayLayout.setActionBar(this);
}
mActionView = (ActionBarView) activity.findViewById(R.id.action_bar);
mContextView = (ActionBarContextView) activity.findViewById(R.id.action_context_bar);
mContainerView = (ActionBarContainer) activity.findViewById(R.id.action_bar_container);
mTopVisibilityView = (ViewGroup) activity.findViewById(R.id.top_action_bar);
if (mTopVisibilityView == null) {
mTopVisibilityView = mContainerView;
}
mSplitView = (ActionBarContainer) activity.findViewById(R.id.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;
// This was initially read from the action bar style
final int current = mActionView.getDisplayOptions();
final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0;
if (homeAsUp) {
mDisplayHomeAsUpSet = true;
}
ActionBarPolicy abp = ActionBarPolicy.get(mContext);
setHomeButtonEnabled(abp.enableHomeButtonByDefault() || homeAsUp);
setHasEmbeddedTabs(abp.hasEmbeddedTabs());
setTitle(mActivity.getTitle());
}
public void onConfigurationChanged(Configuration newConfig) {
setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs());
}
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) {
if (isInTabMode) {
mTabScrollView.setVisibility(View.VISIBLE);
} else {
mTabScrollView.setVisibility(View.GONE);
}
}
mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
}
public boolean hasNonEmbeddedTabs() {
return !mHasEmbeddedTabs && getNavigationMode() == NAVIGATION_MODE_TABS;
}
@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 setCustomView(int resId) {
setCustomView(LayoutInflater.from(getThemedContext())
.inflate(resId, mActionView, false));
}
@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);
}
@Override
public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
mActionView.setDropdownAdapter(adapter);
mActionView.setCallback(callback);
}
@Override
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");
}
}
@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 void setTitle(CharSequence title) {
mActionView.setTitle(title);
}
@Override
public void setTitle(int resId) {
setTitle(mContext.getString(resId));
}
@Override
public void setSubtitle(CharSequence subtitle) {
mActionView.setSubtitle(subtitle);
}
@Override
public void setSubtitle(int resId) {
setSubtitle(mContext.getString(resId));
}
@Override
public void setDisplayOptions(int options) {
if ((options & DISPLAY_HOME_AS_UP) != 0) {
mDisplayHomeAsUpSet = true;
}
mActionView.setDisplayOptions(options);
}
@Override
public void setDisplayOptions(int options, int mask) {
final int current = mActionView.getDisplayOptions();
if ((mask & DISPLAY_HOME_AS_UP) != 0) {
mDisplayHomeAsUpSet = true;
}
mActionView.setDisplayOptions((options & mask) | (current & ~mask));
}
@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 setBackgroundDrawable(Drawable d) {
mContainerView.setPrimaryBackground(d);
}
@Override
public View getCustomView() {
return mActionView.getCustomNavigationView();
}
@Override
public CharSequence getTitle() {
return mActionView.getTitle();
}
@Override
public CharSequence getSubtitle() {
return mActionView.getSubtitle();
}
@Override
public int getNavigationMode() {
return mActionView.getNavigationMode();
}
@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 int getDisplayOptions() {
return mActionView.getDisplayOptions();
}
@Override
public Tab newTab() {
return new TabImpl();
}
@Override
public void addTab(Tab tab) {
addTab(tab, 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) {
addTab(tab, position, mTabs.isEmpty());
}
@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 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 removeAllTabs() {
cleanupTabs();
}
@Override
public void selectTab(Tab tab) {
if (getNavigationMode() != NAVIGATION_MODE_TABS) {
mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
return;
}
final FragmentTransaction trans = 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.isEmpty()) {
trans.commit();
}
}
@Override
public Tab getSelectedTab() {
return mSelectedTab;
}
@Override
public Tab getTabAt(int index) {
return mTabs.get(index);
}
@Override
public int getTabCount() {
return mTabs.size();
}
@Override
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) {
mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
} else {
mThemedContext = mContext;
}
}
return mThemedContext;
}
@Override
public int getHeight() {
return mContainerView.getHeight();
}
@Override
public void show() {
if (mHiddenByApp) {
mHiddenByApp = false;
updateVisibility(false);
}
}
void showForActionMode() {
if (!mShowingForMode) {
mShowingForMode = true;
updateVisibility(false);
}
}
@Override
public void hide() {
if (!mHiddenByApp) {
mHiddenByApp = true;
updateVisibility(false);
}
}
void hideForActionMode() {
if (mShowingForMode) {
mShowingForMode = false;
updateVisibility(false);
}
}
@Override
public boolean isShowing() {
return mNowShowing;
}
@Override
public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
mMenuVisibilityListeners.add(listener);
}
@Override
public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
mMenuVisibilityListeners.remove(listener);
}
public ActionMode startActionMode(ActionMode.Callback callback) {
if (mActionMode != null) {
mActionMode.finish();
}
mContextView.killMode();
ActionModeImpl mode = new ActionModeImpl(callback);
if (mode.dispatchOnCreate()) {
mode.invalidate();
mContextView.initForMode(mode);
animateToMode(true);
if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
if (mSplitView.getVisibility() != View.VISIBLE) {
mSplitView.setVisibility(View.VISIBLE);
}
}
mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
mActionMode = mode;
return mode;
}
return null;
}
void animateToMode(boolean toActionMode) {
if (toActionMode) {
showForActionMode();
} else {
hideForActionMode();
}
mActionView.animateToVisibility(toActionMode ? View.INVISIBLE : View.VISIBLE);
mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) {
mTabScrollView.setVisibility(toActionMode ? View.GONE : View.VISIBLE);
}
}
/**
* @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;
}
}
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(SupportMenuItem.SHOW_AS_ACTION_IF_ROOM);
mMenu.setCallback(this);
}
@Override
public MenuInflater getMenuInflater() {
return new SupportMenuInflater(getThemedContext());
}
@Override
public Menu getMenu() {
return mMenu;
}
@Override
public void finish() {
if (mActionMode != this) {
// Not the active action mode - no-op
return;
}
// If this change in state is going to cause the action bar
// to be hidden, 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 (!checkShowingFlags(mHiddenByApp, mHiddenBySystem, false)) {
// With the current state but the action bar hidden, our
// overall showing state is going to be false.
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;
}
@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 void setTitleOptionalHint(boolean titleOptional) {
super.setTitleOptionalHint(titleOptional);
mContextView.setTitleOptional(titleOptional);
}
@Override
public boolean isTitleOptional() {
return mContextView.isTitleOptional();
}
@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;
}
}
@Override
public void onMenuModeChange(MenuBuilder menu) {
if (mCallback == null) {
return;
}
invalidate();
mContextView.showOverflowMenu();
}
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(Menu menu) {
if (mCallback == null) {
return;
}
invalidate();
mContextView.showOverflowMenu();
}
}
private void ensureTabsExist() {
if (mTabScrollView != null) {
return;
}
ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext);
if (mHasEmbeddedTabs) {
tabScroller.setVisibility(View.VISIBLE);
mActionView.setEmbeddedTabView(tabScroller);
} else {
if (getNavigationMode() == NAVIGATION_MODE_TABS) {
tabScroller.setVisibility(View.VISIBLE);
} else {
tabScroller.setVisibility(View.GONE);
}
mContainerView.setTabContainer(tabScroller);
}
mTabScrollView = tabScroller;
}
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);
}
}
private void cleanupTabs() {
if (mSelectedTab != null) {
selectTab(null);
}
mTabs.clear();
if (mTabScrollView != null) {
mTabScrollView.removeAllTabs();
}
mSavedTabPosition = INVALID_POSITION;
}
private static boolean checkShowingFlags(boolean hiddenByApp, boolean hiddenBySystem,
boolean showingForMode) {
if (showingForMode) {
return true;
} else if (hiddenByApp || hiddenBySystem) {
return false;
} else {
return true;
}
}
private void updateVisibility(boolean fromSystem) {
// Based on the current state, should we be hidden or shown?
final boolean shown = checkShowingFlags(mHiddenByApp, mHiddenBySystem, mShowingForMode);
if (shown) {
if (!mNowShowing) {
mNowShowing = true;
doShow(fromSystem);
}
} else {
if (mNowShowing) {
mNowShowing = false;
doHide(fromSystem);
}
}
}
public void setShowHideAnimationEnabled(boolean enabled) {
mShowHideAnimationEnabled = enabled;
if (!enabled) {
mTopVisibilityView.clearAnimation();
if (mSplitView != null) {
mSplitView.clearAnimation();
}
}
}
public void doShow(boolean fromSystem) {
mTopVisibilityView.clearAnimation();
if (mTopVisibilityView.getVisibility() == View.VISIBLE) {
return;
}
final boolean animate = isShowHideAnimationEnabled() || fromSystem;
if (animate) {
Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.abc_slide_in_top);
mTopVisibilityView.startAnimation(anim);
}
mTopVisibilityView.setVisibility(View.VISIBLE);
if (mSplitView != null && mSplitView.getVisibility() != View.VISIBLE) {
if (animate) {
Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.abc_slide_in_bottom);
mSplitView.startAnimation(anim);
}
mSplitView.setVisibility(View.VISIBLE);
}
}
public void doHide(boolean fromSystem) {
mTopVisibilityView.clearAnimation();
if (mTopVisibilityView.getVisibility() == View.GONE) {
return;
}
final boolean animate = isShowHideAnimationEnabled() || fromSystem;
if (animate) {
Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.abc_slide_out_top);
mTopVisibilityView.startAnimation(anim);
}
mTopVisibilityView.setVisibility(View.GONE);
if (mSplitView != null && mSplitView.getVisibility() != View.GONE) {
if (animate) {
Animation anim = AnimationUtils
.loadAnimation(mContext, R.anim.abc_slide_out_bottom);
mSplitView.startAnimation(anim);
}
mSplitView.setVisibility(View.GONE);
}
}
boolean isShowHideAnimationEnabled() {
return mShowHideAnimationEnabled;
}
}
/*
* Copyright (C) 2013 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 android.support.v7.app;
import android.annotation.TargetApi;
import android.os.Build;
import android.support.v7.internal.widget.NativeActionModeAwareLayout;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
class ActionBarImplCompatHC extends ActionBarImplCompatBase
implements NativeActionModeAwareLayout.OnActionModeForChildListener {
final NativeActionModeAwareLayout mNativeActionModeAwareLayout;
private ActionMode mCurActionMode;
public ActionBarImplCompatHC(ActionBarPreferenceActivity activity, Callback callback) {
super(activity, callback);
// NativeActionModeAwareLayout is used to notify us whena native Action Mode is started
mNativeActionModeAwareLayout = (NativeActionModeAwareLayout) activity
.findViewById(R.id.action_bar_root);
// Can be null when using FEATURE_ACTION_BAR_OVERLAY
if (mNativeActionModeAwareLayout != null) {
mNativeActionModeAwareLayout.setActionModeForChildListener(this);
}
}
// From NativeActionModeAwareLayout.OnActionModeForChildListener
@Override
public ActionMode.Callback onActionModeForChild(ActionMode.Callback callback) {
return new CallbackWrapper(callback);
}
@Override
public void show() {
super.show();
if (mCurActionMode != null) {
mCurActionMode.finish();
}
}
@Override
public void hide() {
super.hide();
if (mCurActionMode != null) {
mCurActionMode.finish();
}
}
@Override
boolean isShowHideAnimationEnabled() {
// Only allow animation if we're not currently showing an action mode
return mCurActionMode == null && super.isShowHideAnimationEnabled();
}
private class CallbackWrapper implements ActionMode.Callback {
private final ActionMode.Callback mWrappedCallback;
CallbackWrapper(ActionMode.Callback callback) {
mWrappedCallback = callback;
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
final boolean wrappedResult = mWrappedCallback.onCreateActionMode(mode, menu);
if (wrappedResult) {
// Keep reference to action mode
mCurActionMode = mode;
// Make sure that the compat Action Bar is shown
showForActionMode();
}
return wrappedResult;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return mWrappedCallback.onPrepareActionMode(mode, menu);
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return mWrappedCallback.onActionItemClicked(mode, item);
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mWrappedCallback.onDestroyActionMode(mode);
// We previously shown the Action Bar for positioning purposes, now hide it again
hideForActionMode();
// Remove any reference to the mode
mCurActionMode = null;
}
}
}
/*
* Copyright (C) 2012 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 android.support.v7.app;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.view.View;
import android.widget.SpinnerAdapter;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
class ActionBarImplCompatICS extends ActionBar {
final Activity mActivity;
final Callback mCallback;
final android.app.ActionBar mActionBar;
private ArrayList<WeakReference<OnMenuVisibilityListenerWrapper>> mAddedMenuVisWrappers =
new ArrayList<WeakReference<OnMenuVisibilityListenerWrapper>>();
public ActionBarImplCompatICS(Activity activity, Callback callback) {
mActivity = activity;
mCallback = callback;
mActionBar = activity.getActionBar();
}
private OnMenuVisibilityListenerWrapper findAndRemoveMenuVisWrapper(
OnMenuVisibilityListener compatListener) {
for (int i = 0; i < mAddedMenuVisWrappers.size(); i++) {
OnMenuVisibilityListenerWrapper wrapper = mAddedMenuVisWrappers.get(i).get();
if (wrapper == null) {
mAddedMenuVisWrappers.remove(i--);
} else if (wrapper.mWrappedListener == compatListener) {
mAddedMenuVisWrappers.remove(i);
return wrapper;
}
}
return null;
}
@Override
public void setCustomView(View view) {
mActionBar.setCustomView(view);
}
@Override
public void setCustomView(View view, LayoutParams layoutParams) {
android.app.ActionBar.LayoutParams lp =
new android.app.ActionBar.LayoutParams(layoutParams);
lp.gravity = layoutParams.gravity;
mActionBar.setCustomView(view, lp);
}
@Override
public void setCustomView(int resId) {
mActionBar.setCustomView(resId);
}
@Override
public void setIcon(int resId) {
mActionBar.setIcon(resId);
}
@Override
public void setIcon(Drawable icon) {
mActionBar.setIcon(icon);
}
@Override
public void setLogo(int resId) {
mActionBar.setLogo(resId);
}
@Override
public void setLogo(Drawable logo) {
mActionBar.setLogo(logo);
}
@Override
public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
mActionBar.setListNavigationCallbacks(adapter,
callback != null ? new OnNavigationListenerWrapper(callback) : null);
}
@Override
public void setSelectedNavigationItem(int position) {
mActionBar.setSelectedNavigationItem(position);
}
@Override
public int getSelectedNavigationIndex() {
return mActionBar.getSelectedNavigationIndex();
}
@Override
public int getNavigationItemCount() {
return mActionBar.getNavigationItemCount();
}
@Override
public void setTitle(CharSequence title) {
mActionBar.setTitle(title);
}
@Override
public void setTitle(int resId) {
mActionBar.setTitle(resId);
}
@Override
public void setSubtitle(CharSequence subtitle) {
mActionBar.setSubtitle(subtitle);
}
@Override
public void setSubtitle(int resId) {
mActionBar.setSubtitle(resId);
}
@Override
public void setDisplayOptions(int options) {
mActionBar.setDisplayOptions(options);
}
@Override
public void setDisplayOptions(int options, int mask) {
mActionBar.setDisplayOptions(options, mask);
}
@Override
public void setDisplayUseLogoEnabled(boolean useLogo) {
mActionBar.setDisplayUseLogoEnabled(useLogo);
}
@Override
public void setDisplayShowHomeEnabled(boolean showHome) {
mActionBar.setDisplayShowHomeEnabled(showHome);
}
@Override
public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
mActionBar.setDisplayHomeAsUpEnabled(showHomeAsUp);
}
@Override
public void setDisplayShowTitleEnabled(boolean showTitle) {
mActionBar.setDisplayShowTitleEnabled(showTitle);
}
@Override
public void setDisplayShowCustomEnabled(boolean showCustom) {
mActionBar.setDisplayShowCustomEnabled(showCustom);
}
@Override
public void setBackgroundDrawable(Drawable d) {
mActionBar.setBackgroundDrawable(d);
}
@Override
public View getCustomView() {
return mActionBar.getCustomView();
}
@Override
public CharSequence getTitle() {
return mActionBar.getTitle();
}
@Override
public CharSequence getSubtitle() {
return mActionBar.getSubtitle();
}
@Override
public int getNavigationMode() {
return mActionBar.getNavigationMode();
}
@Override
public void setNavigationMode(int mode) {
mActionBar.setNavigationMode(mode);
}
@Override
public int getDisplayOptions() {
return mActionBar.getDisplayOptions();
}
@Override
public Tab newTab() {
final android.app.ActionBar.Tab realTab = mActionBar.newTab();
final TabWrapper result = new TabWrapper(realTab);
realTab.setTag(result);
return result;
}
@Override
public void addTab(Tab tab) {
mActionBar.addTab(((TabWrapper) tab).mWrappedTab);
}
@Override
public void addTab(Tab tab, boolean setSelected) {
mActionBar.addTab(((TabWrapper) tab).mWrappedTab, setSelected);
}
@Override
public void addTab(Tab tab, int position) {
mActionBar.addTab(((TabWrapper) tab).mWrappedTab, position);
}
@Override
public void addTab(Tab tab, int position, boolean setSelected) {
mActionBar.addTab(((TabWrapper) tab).mWrappedTab, position, setSelected);
}
@Override
public void removeTab(Tab tab) {
mActionBar.removeTab(((TabWrapper) tab).mWrappedTab);
}
@Override
public void removeTabAt(int position) {
mActionBar.removeTabAt(position);
}
@Override
public void removeAllTabs() {
mActionBar.removeAllTabs();
}
@Override
public void selectTab(Tab tab) {
mActionBar.selectTab(((TabWrapper) tab).mWrappedTab);
}
@Override
public Tab getSelectedTab() {
return (Tab) mActionBar.getSelectedTab().getTag();
}
@Override
public Tab getTabAt(int index) {
return (Tab) mActionBar.getTabAt(index).getTag();
}
@Override
public int getTabCount() {
return mActionBar.getTabCount();
}
@Override
public Context getThemedContext() {
return mActionBar.getThemedContext();
}
@Override
public int getHeight() {
return mActionBar.getHeight();
}
@Override
public void show() {
mActionBar.show();
}
@Override
public void hide() {
mActionBar.hide();
}
@Override
public boolean isShowing() {
return mActionBar.isShowing();
}
@Override
public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
if (listener != null) {
OnMenuVisibilityListenerWrapper w = new OnMenuVisibilityListenerWrapper(listener);
mAddedMenuVisWrappers.add(new WeakReference<OnMenuVisibilityListenerWrapper>(w));
mActionBar.addOnMenuVisibilityListener(w);
}
}
@Override
public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
OnMenuVisibilityListenerWrapper l = findAndRemoveMenuVisWrapper(listener);
mActionBar.removeOnMenuVisibilityListener(l);
}
static class OnNavigationListenerWrapper implements android.app.ActionBar.OnNavigationListener {
private final OnNavigationListener mWrappedListener;
public OnNavigationListenerWrapper(OnNavigationListener l) {
mWrappedListener = l;
}
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
return mWrappedListener.onNavigationItemSelected(itemPosition, itemId);
}
}
static class OnMenuVisibilityListenerWrapper implements
android.app.ActionBar.OnMenuVisibilityListener {
final OnMenuVisibilityListener mWrappedListener;
public OnMenuVisibilityListenerWrapper(OnMenuVisibilityListener l) {
mWrappedListener = l;
}
@Override
public void onMenuVisibilityChanged(boolean isVisible) {
mWrappedListener.onMenuVisibilityChanged(isVisible);
}
}
class TabWrapper extends ActionBar.Tab implements android.app.ActionBar.TabListener {
final android.app.ActionBar.Tab mWrappedTab;
private Object mTag;
private FragmentTransaction mActiveTransaction;
private CharSequence mContentDescription;
private TabListener mTabListener;
public TabWrapper(android.app.ActionBar.Tab tab) {
mWrappedTab = tab;
}
@Override
public int getPosition() {
return mWrappedTab.getPosition();
}
@Override
public Drawable getIcon() {
return mWrappedTab.getIcon();
}
@Override
public CharSequence getText() {
return mWrappedTab.getText();
}
@Override
public Tab setIcon(Drawable icon) {
mWrappedTab.setIcon(icon);
return this;
}
@Override
public Tab setIcon(int resId) {
mWrappedTab.setIcon(resId);
return this;
}
@Override
public Tab setText(CharSequence text) {
mWrappedTab.setText(text);
return this;
}
@Override
public Tab setText(int resId) {
mWrappedTab.setText(resId);
return this;
}
@Override
public Tab setCustomView(View view) {
mWrappedTab.setCustomView(view);
return this;
}
@Override
public Tab setCustomView(int layoutResId) {
mWrappedTab.setCustomView(layoutResId);
return this;
}
@Override
public View getCustomView() {
return mWrappedTab.getCustomView();
}
@Override
public Tab setTag(Object obj) {
mTag = obj;
return this;
}
@Override
public Object getTag() {
return mTag;
}
@Override
public Tab setTabListener(TabListener listener) {
mTabListener = listener;
mWrappedTab.setTabListener(listener != null ? this : null);
return this;
}
@Override
public void select() {
mWrappedTab.select();
}
@Override
public Tab setContentDescription(int resId) {
mContentDescription = mActivity.getText(resId);
return this;
}
@Override
public Tab setContentDescription(CharSequence contentDesc) {
mContentDescription = contentDesc;
return this;
}
@Override
public CharSequence getContentDescription() {
return mContentDescription;
}
@Override
public void onTabSelected(android.app.ActionBar.Tab tab,
android.app.FragmentTransaction ft) {
mTabListener.onTabSelected(this, ft != null ? getActiveTransaction() : null);
commitActiveTransaction();
}
@Override
public void onTabUnselected(android.app.ActionBar.Tab tab,
android.app.FragmentTransaction ft) {
mTabListener.onTabUnselected(this, ft != null ? getActiveTransaction() : null);
}
@Override
public void onTabReselected(android.app.ActionBar.Tab tab,
android.app.FragmentTransaction ft) {
mTabListener.onTabReselected(this, ft != null ? getActiveTransaction() : null);
commitActiveTransaction();
}
private FragmentTransaction getActiveTransaction() {
if (mActiveTransaction == null) {
mActiveTransaction = mCallback.getSupportFragmentManager().beginTransaction()
.disallowAddToBackStack();
}
return mActiveTransaction;
}
private void commitActiveTransaction() {
if (mActiveTransaction != null && !mActiveTransaction.isEmpty()) {
mActiveTransaction.commit();
}
mActiveTransaction = null;
}
}
}
package android.support.v7.app;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.NavUtils;
import android.support.v4.app.TaskStackBuilder;
import android.support.v4.view.WindowCompat;
import android.support.v7.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
public class ActionBarPreferenceActivity extends PreferenceActivity implements ActionBar.Callback,
TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {
ActionBarActivityDelegateCompat mImpl;
/**
* Support library version of {@link Activity#getActionBar}.
*
* <p>Retrieve a reference to this activity's ActionBar.
*
* @return The Activity's ActionBar, or null if it does not have one.
*/
public ActionBar getSupportActionBar() {
return mImpl.getSupportActionBar();
}
@Override
public MenuInflater getMenuInflater() {
return mImpl.getMenuInflater();
}
@Override
public void setContentView(int layoutResID) {
mImpl.setContentView(layoutResID);
}
@Override
public void setContentView(View view) {
mImpl.setContentView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
mImpl.setContentView(view, params);
}
@Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
mImpl.addContentView(view, params);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
mImpl = ActionBarActivityDelegateCompat.createDelegate(this);
super.onCreate(savedInstanceState);
mImpl.onCreate(savedInstanceState);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mImpl.onConfigurationChanged(newConfig);
}
@Override
protected void onStop() {
super.onStop();
mImpl.onStop();
}
@Override
protected void onPostResume() {
super.onPostResume();
mImpl.onPostResume();
}
@Override
public View onCreatePanelView(int featureId) {
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
return mImpl.onCreatePanelView(featureId);
} else {
return super.onCreatePanelView(featureId);
}
}
@Override
public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) {
if (mImpl.onMenuItemSelected(featureId, item)) {
return true;
}
final ActionBar ab = getSupportActionBar();
if (item.getItemId() == android.R.id.home && ab != null &&
(ab.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
return onSupportNavigateUp();
}
return false;
}
@Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
mImpl.setTitle(title);
}
/**
* Enable extended support library window features.
* <p>
* This is a convenience for calling
* {@link android.view.Window#requestFeature getWindow().requestFeature()}.
* </p>
*
* @param featureId The desired feature as defined in
* {@link android.view.Window} or {@link WindowCompat}.
* @return Returns true if the requested feature is supported and now enabled.
*
* @see android.app.Activity#requestWindowFeature
* @see android.view.Window#requestFeature
*/
public boolean supportRequestWindowFeature(int featureId) {
return mImpl.supportRequestWindowFeature(featureId);
}
@SuppressLint("NewApi")
@Override
public void invalidateOptionsMenu() {
// Only call up to super on ICS+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
super.invalidateOptionsMenu();
}
mImpl.supportInvalidateOptionsMenu();
}
/**
* Notifies the Activity that a support action mode has been started.
* Activity subclasses overriding this method should call the superclass implementation.
*
* @param mode The new action mode.
*/
public void onSupportActionModeStarted(ActionMode mode) {
}
/**
* Notifies the activity that a support action mode has finished.
* Activity subclasses overriding this method should call the superclass implementation.
*
* @param mode The action mode that just finished.
*/
public void onSupportActionModeFinished(ActionMode mode) {
}
public ActionMode startSupportActionMode(ActionMode.Callback callback) {
return mImpl.startSupportActionMode(callback);
}
@Override
public boolean onCreatePanelMenu(int featureId, Menu menu) {
return mImpl.onCreatePanelMenu(featureId, menu);
}
@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
return mImpl.onPreparePanel(featureId, view, menu);
}
void superSetContentView(int resId) {
super.setContentView(resId);
}
void superSetContentView(View v) {
super.setContentView(v);
}
void superSetContentView(View v, ViewGroup.LayoutParams lp) {
super.setContentView(v, lp);
}
void superAddContentView(View v, ViewGroup.LayoutParams lp) {
super.addContentView(v, lp);
}
boolean superOnCreatePanelMenu(int featureId, android.view.Menu frameworkMenu) {
return super.onCreatePanelMenu(featureId, frameworkMenu);
}
boolean superOnPreparePanel(int featureId, View view, android.view.Menu menu) {
return super.onPreparePanel(featureId, view, menu);
}
boolean superOnMenuItemSelected(int featureId, MenuItem menuItem) {
return super.onMenuItemSelected(featureId, menuItem);
}
@Override
public void onBackPressed() {
if (!mImpl.onBackPressed()) {
super.onBackPressed();
}
}
/**
* Support library version of {@link Activity#setProgressBarVisibility(boolean)}
* <p>
* Sets the visibility of the progress bar in the title.
* <p>
* In order for the progress bar to be shown, the feature must be requested
* via {@link #supportRequestWindowFeature(int)}.
*
* @param visible Whether to show the progress bars in the title.
*/
public void setSupportProgressBarVisibility(boolean visible) {
mImpl.setSupportProgressBarVisibility(visible);
}
/**
* Support library version of {@link Activity#setProgressBarIndeterminateVisibility(boolean)}
* <p>
* Sets the visibility of the indeterminate progress bar in the title.
* <p>
* In order for the progress bar to be shown, the feature must be requested
* via {@link #supportRequestWindowFeature(int)}.
*
* @param visible Whether to show the progress bars in the title.
*/
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
mImpl.setSupportProgressBarIndeterminateVisibility(visible);
}
/**
* Support library version of {@link Activity#setProgressBarIndeterminate(boolean)}
* <p>
* Sets whether the horizontal progress bar in the title should be indeterminate (the
* circular is always indeterminate).
* <p>
* In order for the progress bar to be shown, the feature must be requested
* via {@link #supportRequestWindowFeature(int)}.
*
* @param indeterminate Whether the horizontal progress bar should be indeterminate.
*/
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
mImpl.setSupportProgressBarIndeterminate(indeterminate);
}
/**
* Support library version of {@link Activity#setProgress(int)}.
* <p>
* Sets the progress for the progress bars in the title.
* <p>
* In order for the progress bar to be shown, the feature must be requested
* via {@link #supportRequestWindowFeature(int)}.
*
* @param progress The progress for the progress bar. Valid ranges are from
* 0 to 10000 (both inclusive). If 10000 is given, the progress
* bar will be completely filled and will fade out.
*/
public void setSupportProgress(int progress) {
mImpl.setSupportProgress(progress);
}
/**
* Support version of {@link #onCreateNavigateUpTaskStack(android.app.TaskStackBuilder)}.
* This method will be called on all platform versions.
*
* Define the synthetic task stack that will be generated during Up navigation from
* a different task.
*
* <p>The default implementation of this method adds the parent chain of this activity
* as specified in the manifest to the supplied {@link TaskStackBuilder}. Applications
* may choose to override this method to construct the desired task stack in a different
* way.</p>
*
* <p>This method will be invoked by the default implementation of {@link #onNavigateUp()}
* if {@link #shouldUpRecreateTask(Intent)} returns true when supplied with the intent
* returned by {@link #getParentActivityIntent()}.</p>
*
* <p>Applications that wish to supply extra Intent parameters to the parent stack defined
* by the manifest should override
* {@link #onPrepareSupportNavigateUpTaskStack(TaskStackBuilder)}.</p>
*
* @param builder An empty TaskStackBuilder - the application should add intents representing
* the desired task stack
*/
public void onCreateSupportNavigateUpTaskStack(TaskStackBuilder builder) {
builder.addParentStack(this);
}
/**
* Support version of {@link #onPrepareNavigateUpTaskStack(android.app.TaskStackBuilder)}.
* This method will be called on all platform versions.
*
* Prepare the synthetic task stack that will be generated during Up navigation
* from a different task.
*
* <p>This method receives the {@link TaskStackBuilder} with the constructed series of
* Intents as generated by {@link #onCreateSupportNavigateUpTaskStack(TaskStackBuilder)}.
* If any extra data should be added to these intents before launching the new task,
* the application should override this method and add that data here.</p>
*
* @param builder A TaskStackBuilder that has been populated with Intents by
* onCreateNavigateUpTaskStack.
*/
public void onPrepareSupportNavigateUpTaskStack(TaskStackBuilder builder) {
}
/**
* This method is called whenever the user chooses to navigate Up within your application's
* activity hierarchy from the action bar.
*
* <p>If a parent was specified in the manifest for this activity or an activity-alias to it,
* default Up navigation will be handled automatically. See
* {@link #getSupportParentActivityIntent()} for how to specify the parent. If any activity
* along the parent chain requires extra Intent arguments, the Activity subclass
* should override the method {@link #onPrepareSupportNavigateUpTaskStack(TaskStackBuilder)}
* to supply those arguments.</p>
*
* <p>See <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and
* Back Stack</a> from the developer guide and
* <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> from the design guide
* for more information about navigating within your app.</p>
*
* <p>See the {@link TaskStackBuilder} class and the Activity methods
* {@link #getSupportParentActivityIntent()}, {@link #supportShouldUpRecreateTask(Intent)}, and
* {@link #supportNavigateUpTo(Intent)} for help implementing custom Up navigation.</p>
*
* @return true if Up navigation completed successfully and this Activity was finished,
* false otherwise.
*/
public boolean onSupportNavigateUp() {
Intent upIntent = getSupportParentActivityIntent();
if (upIntent != null) {
if (supportShouldUpRecreateTask(upIntent)) {
TaskStackBuilder b = TaskStackBuilder.create(this);
onCreateSupportNavigateUpTaskStack(b);
onPrepareSupportNavigateUpTaskStack(b);
b.startActivities();
try {
ActivityCompat.finishAffinity(this);
} catch (IllegalStateException e) {
// This can only happen on 4.1+, when we don't have a parent or a result set.
// In that case we should just finish().
finish();
}
} else {
// This activity is part of the application's task, so simply
// navigate up to the hierarchical parent activity.
supportNavigateUpTo(upIntent);
}
return true;
}
return false;
}
/**
* Obtain an {@link Intent} that will launch an explicit target activity
* specified by sourceActivity's {@link NavUtils#PARENT_ACTIVITY} &lt;meta-data&gt;
* element in the application's manifest. If the device is running
* Jellybean or newer, the android:parentActivityName attribute will be preferred
* if it is present.
*
* @return a new Intent targeting the defined parent activity of sourceActivity
*/
public Intent getSupportParentActivityIntent() {
return NavUtils.getParentActivityIntent(this);
}
/**
* Returns true if sourceActivity should recreate the task when navigating 'up'
* by using targetIntent.
*
* <p>If this method returns false the app can trivially call
* {@link #supportNavigateUpTo(Intent)} using the same parameters to correctly perform
* up navigation. If this method returns false, the app should synthesize a new task stack
* by using {@link TaskStackBuilder} or another similar mechanism to perform up navigation.</p>
*
* @param targetIntent An intent representing the target destination for up navigation
* @return true if navigating up should recreate a new task stack, false if the same task
* should be used for the destination
*/
public boolean supportShouldUpRecreateTask(Intent targetIntent) {
return NavUtils.shouldUpRecreateTask(this, targetIntent);
}
/**
* Navigate from sourceActivity to the activity specified by upIntent, finishing sourceActivity
* in the process. upIntent will have the flag {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} set
* by this method, along with any others required for proper up navigation as outlined
* in the Android Design Guide.
*
* <p>This method should be used when performing up navigation from within the same task
* as the destination. If up navigation should cross tasks in some cases, see
* {@link #supportShouldUpRecreateTask(Intent)}.</p>
*
* @param upIntent An intent representing the target destination for up navigation
*/
public void supportNavigateUpTo(Intent upIntent) {
NavUtils.navigateUpTo(this, upIntent);
}
@Override
public final ActionBarDrawerToggle.Delegate getDrawerToggleDelegate() {
return mImpl.getDrawerToggleDelegate();
}
@Override
public FragmentManager getSupportFragmentManager() {
new UnsupportedOperationException("not allowed in PreferenceActivity()").printStackTrace();
return null;
}
}
@XinyueZ
Copy link

XinyueZ commented Jul 25, 2014

Can not run on pre 4.0 Devices like 2.3. You should improve it.

@mburumaxwell
Copy link
Author

I wasn't writing it for android 2.3 initially because it contributes to a very small percentage of devices. My aim was thumbing on 4.0+. Hopefully, you can check where there are issues and suggest some changes, since you have access to a testing device running 2.3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment