aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java')
-rw-r--r--libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java1203
1 files changed, 1203 insertions, 0 deletions
diff --git a/libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java b/libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java
new file mode 100644
index 000000000..5e69275c7
--- /dev/null
+++ b/libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java
@@ -0,0 +1,1203 @@
+package com.actionbarsherlock.internal;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import org.xmlpull.v1.XmlPullParser;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+import android.view.Window;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+import com.actionbarsherlock.ActionBarSherlock;
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.internal.app.ActionBarImpl;
+import com.actionbarsherlock.internal.view.StandaloneActionMode;
+import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
+import com.actionbarsherlock.internal.view.menu.MenuBuilder;
+import com.actionbarsherlock.internal.view.menu.MenuItemImpl;
+import com.actionbarsherlock.internal.view.menu.MenuPresenter;
+import com.actionbarsherlock.internal.widget.ActionBarContainer;
+import com.actionbarsherlock.internal.widget.ActionBarContextView;
+import com.actionbarsherlock.internal.widget.ActionBarView;
+import com.actionbarsherlock.internal.widget.IcsProgressBar;
+import com.actionbarsherlock.view.ActionMode;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+
+@ActionBarSherlock.Implementation(api = 7)
+public class ActionBarSherlockCompat extends ActionBarSherlock implements MenuBuilder.Callback, com.actionbarsherlock.view.Window.Callback, MenuPresenter.Callback, android.view.MenuItem.OnMenuItemClickListener {
+ /** Window features which are enabled by default. */
+ protected static final int DEFAULT_FEATURES = 0;
+
+ static private final String PANELS_TAG = "sherlock:Panels";
+
+ public ActionBarSherlockCompat(Activity activity, int flags) {
+ super(activity, flags);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Properties
+ ///////////////////////////////////////////////////////////////////////////
+
+ /** Whether or not the device has a dedicated menu key button. */
+ private boolean mReserveOverflow;
+ /** Lazy-load indicator for {@link #mReserveOverflow}. */
+ private boolean mReserveOverflowSet = false;
+
+ /** Current menu instance for managing action items. */
+ private MenuBuilder mMenu;
+ /** Map between native options items and sherlock items. */
+ protected HashMap<android.view.MenuItem, MenuItemImpl> mNativeItemMap;
+
+ /** Parent view of the window decoration (action bar, mode, etc.). */
+ private ViewGroup mDecor;
+ /** Parent view of the activity content. */
+ private ViewGroup mContentParent;
+
+ /** Whether or not the title is stable and can be displayed. */
+ private boolean mIsTitleReady = false;
+ /** Whether or not the parent activity has been destroyed. */
+ private boolean mIsDestroyed = false;
+
+ /* Emulate PanelFeatureState */
+ private boolean mClosingActionMenu;
+ private boolean mMenuIsPrepared;
+ private boolean mMenuRefreshContent;
+ private Bundle mMenuFrozenActionViewState;
+
+ /** Implementation which backs the action bar interface API. */
+ private ActionBarImpl aActionBar;
+ /** Main action bar view which displays the core content. */
+ private ActionBarView wActionBar;
+ /** Relevant window and action bar features flags. */
+ private int mFeatures = DEFAULT_FEATURES;
+ /** Relevant user interface option flags. */
+ private int mUiOptions = 0;
+
+ /** Decor indeterminate progress indicator. */
+ private IcsProgressBar mCircularProgressBar;
+ /** Decor progress indicator. */
+ private IcsProgressBar mHorizontalProgressBar;
+
+ /** Current displayed context action bar, if any. */
+ private ActionMode mActionMode;
+ /** Parent view in which the context action bar is displayed. */
+ private ActionBarContextView mActionModeView;
+
+ /** Title view used with dialogs. */
+ private TextView mTitleView;
+ /** Current activity title. */
+ private CharSequence mTitle = null;
+ /** Whether or not this "activity" is floating (i.e., a dialog) */
+ private boolean mIsFloating;
+
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Instance methods
+ ///////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public ActionBar getActionBar() {
+ if (DEBUG) Log.d(TAG, "[getActionBar]");
+
+ initActionBar();
+ return aActionBar;
+ }
+
+ private void initActionBar() {
+ if (DEBUG) Log.d(TAG, "[initActionBar]");
+
+ // Initializing the window decor can change window feature flags.
+ // Make sure that we have the correct set before performing the test below.
+ if (mDecor == null) {
+ installDecor();
+ }
+
+ if ((aActionBar != null) || !hasFeature(Window.FEATURE_ACTION_BAR) || hasFeature(Window.FEATURE_NO_TITLE) || mActivity.isChild()) {
+ return;
+ }
+
+ aActionBar = new ActionBarImpl(mActivity, mFeatures);
+
+ if (!mIsDelegate) {
+ //We may never get another chance to set the title
+ wActionBar.setWindowTitle(mActivity.getTitle());
+ }
+ }
+
+ @Override
+ protected Context getThemedContext() {
+ return aActionBar.getThemedContext();
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ if (DEBUG) Log.d(TAG, "[setTitle] title: " + title);
+
+ dispatchTitleChanged(title, 0);
+ }
+
+ @Override
+ public ActionMode startActionMode(ActionMode.Callback callback) {
+ if (DEBUG) Log.d(TAG, "[startActionMode] callback: " + callback);
+
+ if (mActionMode != null) {
+ mActionMode.finish();
+ }
+
+ final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
+ ActionMode mode = null;
+
+ //Emulate Activity's onWindowStartingActionMode:
+ initActionBar();
+ if (aActionBar != null) {
+ mode = aActionBar.startActionMode(wrappedCallback);
+ }
+
+ if (mode != null) {
+ mActionMode = mode;
+ } else {
+ if (mActionModeView == null) {
+ ViewStub stub = (ViewStub)mDecor.findViewById(R.id.abs__action_mode_bar_stub);
+ if (stub != null) {
+ mActionModeView = (ActionBarContextView)stub.inflate();
+ }
+ }
+ if (mActionModeView != null) {
+ mActionModeView.killMode();
+ mode = new StandaloneActionMode(mActivity, mActionModeView, wrappedCallback, true);
+ if (callback.onCreateActionMode(mode, mode.getMenu())) {
+ mode.invalidate();
+ mActionModeView.initForMode(mode);
+ mActionModeView.setVisibility(View.VISIBLE);
+ mActionMode = mode;
+ mActionModeView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+ } else {
+ mActionMode = null;
+ }
+ }
+ }
+ if (mActionMode != null && mActivity instanceof OnActionModeStartedListener) {
+ ((OnActionModeStartedListener)mActivity).onActionModeStarted(mActionMode);
+ }
+ return mActionMode;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Lifecycle and interaction callbacks for delegation
+ ///////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public void dispatchConfigurationChanged(Configuration newConfig) {
+ if (DEBUG) Log.d(TAG, "[dispatchConfigurationChanged] newConfig: " + newConfig);
+
+ if (aActionBar != null) {
+ aActionBar.onConfigurationChanged(newConfig);
+ }
+ }
+
+ @Override
+ public void dispatchPostResume() {
+ if (DEBUG) Log.d(TAG, "[dispatchPostResume]");
+
+ if (aActionBar != null) {
+ aActionBar.setShowHideAnimationEnabled(true);
+ }
+ }
+
+ @Override
+ public void dispatchPause() {
+ if (DEBUG) Log.d(TAG, "[dispatchPause]");
+
+ if (wActionBar != null && wActionBar.isOverflowMenuShowing()) {
+ wActionBar.hideOverflowMenu();
+ }
+ }
+
+ @Override
+ public void dispatchStop() {
+ if (DEBUG) Log.d(TAG, "[dispatchStop]");
+
+ if (aActionBar != null) {
+ aActionBar.setShowHideAnimationEnabled(false);
+ }
+ }
+
+ @Override
+ public void dispatchInvalidateOptionsMenu() {
+ if (DEBUG) Log.d(TAG, "[dispatchInvalidateOptionsMenu]");
+
+ Bundle savedActionViewStates = null;
+ if (mMenu != null) {
+ savedActionViewStates = new Bundle();
+ mMenu.saveActionViewStates(savedActionViewStates);
+ if (savedActionViewStates.size() > 0) {
+ mMenuFrozenActionViewState = savedActionViewStates;
+ }
+ // This will be started again when the panel is prepared.
+ mMenu.stopDispatchingItemsChanged();
+ mMenu.clear();
+ }
+ mMenuRefreshContent = true;
+
+ // Prepare the options panel if we have an action bar
+ if (wActionBar != null) {
+ mMenuIsPrepared = false;
+ preparePanel();
+ }
+ }
+
+ @Override
+ public boolean dispatchOpenOptionsMenu() {
+ if (DEBUG) Log.d(TAG, "[dispatchOpenOptionsMenu]");
+
+ if (!isReservingOverflow()) {
+ return false;
+ }
+
+ return wActionBar.showOverflowMenu();
+ }
+
+ @Override
+ public boolean dispatchCloseOptionsMenu() {
+ if (DEBUG) Log.d(TAG, "[dispatchCloseOptionsMenu]");
+
+ if (!isReservingOverflow()) {
+ return false;
+ }
+
+ if (wActionBar != null) {
+ return wActionBar.hideOverflowMenu();
+ }
+ return false;
+ }
+
+ @Override
+ public void dispatchPostCreate(Bundle savedInstanceState) {
+ if (DEBUG) Log.d(TAG, "[dispatchOnPostCreate]");
+
+ if (mIsDelegate) {
+ mIsTitleReady = true;
+ }
+
+ if (mDecor == null) {
+ initActionBar();
+ }
+ }
+
+ @Override
+ public boolean dispatchCreateOptionsMenu(android.view.Menu menu) {
+ if (DEBUG) {
+ Log.d(TAG, "[dispatchCreateOptionsMenu] android.view.Menu: " + menu);
+ Log.d(TAG, "[dispatchCreateOptionsMenu] returning true");
+ }
+ return true;
+ }
+
+ @Override
+ public boolean dispatchPrepareOptionsMenu(android.view.Menu menu) {
+ if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] android.view.Menu: " + menu);
+
+ if (mActionMode != null) {
+ return false;
+ }
+
+ mMenuIsPrepared = false;
+ if (!preparePanel()) {
+ return false;
+ }
+
+ if (isReservingOverflow()) {
+ return false;
+ }
+
+ if (mNativeItemMap == null) {
+ mNativeItemMap = new HashMap<android.view.MenuItem, MenuItemImpl>();
+ } else {
+ mNativeItemMap.clear();
+ }
+
+ if (mMenu == null) {
+ return false;
+ }
+
+ boolean result = mMenu.bindNativeOverflow(menu, this, mNativeItemMap);
+ if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] returning " + result);
+ return result;
+ }
+
+ @Override
+ public boolean dispatchOptionsItemSelected(android.view.MenuItem item) {
+ throw new IllegalStateException("Native callback invoked. Create a test case and report!");
+ }
+
+ @Override
+ public boolean dispatchMenuOpened(int featureId, android.view.Menu menu) {
+ if (DEBUG) Log.d(TAG, "[dispatchMenuOpened] featureId: " + featureId + ", menu: " + menu);
+
+ if (featureId == Window.FEATURE_ACTION_BAR || featureId == Window.FEATURE_OPTIONS_PANEL) {
+ if (aActionBar != null) {
+ aActionBar.dispatchMenuVisibilityChanged(true);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void dispatchPanelClosed(int featureId, android.view.Menu menu){
+ if (DEBUG) Log.d(TAG, "[dispatchPanelClosed] featureId: " + featureId + ", menu: " + menu);
+
+ if (featureId == Window.FEATURE_ACTION_BAR || featureId == Window.FEATURE_OPTIONS_PANEL) {
+ if (aActionBar != null) {
+ aActionBar.dispatchMenuVisibilityChanged(false);
+ }
+ }
+ }
+
+ @Override
+ public void dispatchTitleChanged(CharSequence title, int color) {
+ if (DEBUG) Log.d(TAG, "[dispatchTitleChanged] title: " + title + ", color: " + color);
+
+ if (!mIsDelegate || mIsTitleReady) {
+ if (mTitleView != null) {
+ mTitleView.setText(title);
+ } else if (wActionBar != null) {
+ wActionBar.setWindowTitle(title);
+ }
+ }
+
+ mTitle = title;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] event: " + event);
+
+ final int keyCode = event.getKeyCode();
+
+ // Not handled by the view hierarchy, does the action bar want it
+ // to cancel out of something special?
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ final int action = event.getAction();
+ // Back cancels action modes first.
+ if (mActionMode != null) {
+ if (action == KeyEvent.ACTION_UP) {
+ mActionMode.finish();
+ }
+ if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning true");
+ return true;
+ }
+
+ // Next collapse any expanded action views.
+ if (wActionBar != null && wActionBar.hasExpandedActionView()) {
+ if (action == KeyEvent.ACTION_UP) {
+ wActionBar.collapseActionView();
+ }
+ if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning true");
+ return true;
+ }
+ }
+
+ if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning false");
+ return false;
+ }
+
+ @Override
+ public void dispatchDestroy() {
+ mIsDestroyed = true;
+ }
+
+ @Override
+ public void dispatchSaveInstanceState(Bundle outState) {
+ if (mMenu != null) {
+ mMenuFrozenActionViewState = new Bundle();
+ mMenu.saveActionViewStates(mMenuFrozenActionViewState);
+ }
+ outState.putParcelable(PANELS_TAG, mMenuFrozenActionViewState);
+ }
+
+ @Override
+ public void dispatchRestoreInstanceState(Bundle savedInstanceState) {
+ mMenuFrozenActionViewState = savedInstanceState.getParcelable(PANELS_TAG);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Menu callback lifecycle and creation
+ ///////////////////////////////////////////////////////////////////////////
+
+ private boolean preparePanel() {
+ // Already prepared (isPrepared will be reset to false later)
+ if (mMenuIsPrepared) {
+ return true;
+ }
+
+ // Init the panel state's menu--return false if init failed
+ if (mMenu == null || mMenuRefreshContent) {
+ if (mMenu == null) {
+ if (!initializePanelMenu() || (mMenu == null)) {
+ return false;
+ }
+ }
+
+ if (wActionBar != null) {
+ wActionBar.setMenu(mMenu, this);
+ }
+
+ // Call callback, and return if it doesn't want to display menu.
+
+ // Creating the panel menu will involve a lot of manipulation;
+ // don't dispatch change events to presenters until we're done.
+ mMenu.stopDispatchingItemsChanged();
+ if (!callbackCreateOptionsMenu(mMenu)) {
+ // Ditch the menu created above
+ mMenu = null;
+
+ if (wActionBar != null) {
+ // Don't show it in the action bar either
+ wActionBar.setMenu(null, this);
+ }
+
+ return false;
+ }
+
+ mMenuRefreshContent = false;
+ }
+
+ // Callback and return if the callback does not want to show the menu
+
+ // Preparing the panel menu can involve a lot of manipulation;
+ // don't dispatch change events to presenters until we're done.
+ mMenu.stopDispatchingItemsChanged();
+
+ // Restore action view state before we prepare. This gives apps
+ // an opportunity to override frozen/restored state in onPrepare.
+ if (mMenuFrozenActionViewState != null) {
+ mMenu.restoreActionViewStates(mMenuFrozenActionViewState);
+ mMenuFrozenActionViewState = null;
+ }
+
+ if (!callbackPrepareOptionsMenu(mMenu)) {
+ if (wActionBar != null) {
+ // The app didn't want to show the menu for now but it still exists.
+ // Clear it out of the action bar.
+ wActionBar.setMenu(null, this);
+ }
+ mMenu.startDispatchingItemsChanged();
+ return false;
+ }
+
+ // Set the proper keymap
+ KeyCharacterMap kmap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ mMenu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC);
+ mMenu.startDispatchingItemsChanged();
+
+ // Set other state
+ mMenuIsPrepared = true;
+
+ return true;
+ }
+
+ public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+ return callbackOptionsItemSelected(item);
+ }
+
+ public void onMenuModeChange(MenuBuilder menu) {
+ reopenMenu(true);
+ }
+
+ private void reopenMenu(boolean toggleMenuMode) {
+ if (wActionBar != null && wActionBar.isOverflowReserved()) {
+ if (!wActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
+ if (wActionBar.getVisibility() == View.VISIBLE) {
+ if (callbackPrepareOptionsMenu(mMenu)) {
+ wActionBar.showOverflowMenu();
+ }
+ }
+ } else {
+ wActionBar.hideOverflowMenu();
+ }
+ return;
+ }
+ }
+
+ private boolean initializePanelMenu() {
+ Context context = mActivity;//getContext();
+
+ // If we have an action bar, initialize the menu with a context themed for it.
+ if (wActionBar != null) {
+ TypedValue outValue = new TypedValue();
+ Resources.Theme currentTheme = context.getTheme();
+ currentTheme.resolveAttribute(R.attr.actionBarWidgetTheme,
+ outValue, true);
+ final int targetThemeRes = outValue.resourceId;
+
+ if (targetThemeRes != 0 /*&& context.getThemeResId() != targetThemeRes*/) {
+ context = new ContextThemeWrapper(context, targetThemeRes);
+ }
+ }
+
+ mMenu = new MenuBuilder(context);
+ mMenu.setCallback(this);
+
+ return true;
+ }
+
+ void checkCloseActionMenu(Menu menu) {
+ if (mClosingActionMenu) {
+ return;
+ }
+
+ mClosingActionMenu = true;
+ wActionBar.dismissPopupMenus();
+ //Callback cb = getCallback();
+ //if (cb != null && !isDestroyed()) {
+ // cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
+ //}
+ mClosingActionMenu = false;
+ }
+
+ @Override
+ public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ return true;
+ }
+
+ @Override
+ public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+ checkCloseActionMenu(menu);
+ }
+
+ @Override
+ public boolean onMenuItemClick(android.view.MenuItem item) {
+ if (DEBUG) Log.d(TAG, "[mNativeItemListener.onMenuItemClick] item: " + item);
+
+ final MenuItemImpl sherlockItem = mNativeItemMap.get(item);
+ if (sherlockItem != null) {
+ sherlockItem.invoke();
+ } else {
+ Log.e(TAG, "Options item \"" + item + "\" not found in mapping");
+ }
+
+ return true; //Do not allow continuation of native handling
+ }
+
+ @Override
+ public boolean onMenuItemSelected(int featureId, MenuItem item) {
+ return callbackOptionsItemSelected(item);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Progress bar interaction and internal handling
+ ///////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public void setProgressBarVisibility(boolean visible) {
+ if (DEBUG) Log.d(TAG, "[setProgressBarVisibility] visible: " + visible);
+
+ setFeatureInt(Window.FEATURE_PROGRESS, visible ? Window.PROGRESS_VISIBILITY_ON :
+ Window.PROGRESS_VISIBILITY_OFF);
+ }
+
+ @Override
+ public void setProgressBarIndeterminateVisibility(boolean visible) {
+ if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminateVisibility] visible: " + visible);
+
+ setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
+ visible ? Window.PROGRESS_VISIBILITY_ON : Window.PROGRESS_VISIBILITY_OFF);
+ }
+
+ @Override
+ public void setProgressBarIndeterminate(boolean indeterminate) {
+ if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminate] indeterminate: " + indeterminate);
+
+ setFeatureInt(Window.FEATURE_PROGRESS,
+ indeterminate ? Window.PROGRESS_INDETERMINATE_ON : Window.PROGRESS_INDETERMINATE_OFF);
+ }
+
+ @Override
+ public void setProgress(int progress) {
+ if (DEBUG) Log.d(TAG, "[setProgress] progress: " + progress);
+
+ setFeatureInt(Window.FEATURE_PROGRESS, progress + Window.PROGRESS_START);
+ }
+
+ @Override
+ public void setSecondaryProgress(int secondaryProgress) {
+ if (DEBUG) Log.d(TAG, "[setSecondaryProgress] secondaryProgress: " + secondaryProgress);
+
+ setFeatureInt(Window.FEATURE_PROGRESS,
+ secondaryProgress + Window.PROGRESS_SECONDARY_START);
+ }
+
+ private void setFeatureInt(int featureId, int value) {
+ updateInt(featureId, value, false);
+ }
+
+ private void updateInt(int featureId, int value, boolean fromResume) {
+ // Do nothing if the decor is not yet installed... an update will
+ // need to be forced when we eventually become active.
+ if (mContentParent == null) {
+ return;
+ }
+
+ final int featureMask = 1 << featureId;
+
+ if ((getFeatures() & featureMask) == 0 && !fromResume) {
+ return;
+ }
+
+ onIntChanged(featureId, value);
+ }
+
+ private void onIntChanged(int featureId, int value) {
+ if (featureId == Window.FEATURE_PROGRESS || featureId == Window.FEATURE_INDETERMINATE_PROGRESS) {
+ updateProgressBars(value);
+ }
+ }
+
+ private void updateProgressBars(int value) {
+ IcsProgressBar circularProgressBar = getCircularProgressBar(true);
+ IcsProgressBar horizontalProgressBar = getHorizontalProgressBar(true);
+
+ final int features = mFeatures;//getLocalFeatures();
+ if (value == Window.PROGRESS_VISIBILITY_ON) {
+ if ((features & (1 << Window.FEATURE_PROGRESS)) != 0) {
+ int level = horizontalProgressBar.getProgress();
+ int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ?
+ View.VISIBLE : View.INVISIBLE;
+ horizontalProgressBar.setVisibility(visibility);
+ }
+ if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0) {
+ circularProgressBar.setVisibility(View.VISIBLE);
+ }
+ } else if (value == Window.PROGRESS_VISIBILITY_OFF) {
+ if ((features & (1 << Window.FEATURE_PROGRESS)) != 0) {
+ horizontalProgressBar.setVisibility(View.GONE);
+ }
+ if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0) {
+ 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);
+ }
+ } else if (Window.PROGRESS_SECONDARY_START <= value && value <= Window.PROGRESS_SECONDARY_END) {
+ horizontalProgressBar.setSecondaryProgress(value - Window.PROGRESS_SECONDARY_START);
+
+ showProgressBars(horizontalProgressBar, circularProgressBar);
+ }
+ }
+
+ private void showProgressBars(IcsProgressBar horizontalProgressBar, IcsProgressBar spinnyProgressBar) {
+ final int features = mFeatures;//getLocalFeatures();
+ if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
+ spinnyProgressBar.getVisibility() == View.INVISIBLE) {
+ spinnyProgressBar.setVisibility(View.VISIBLE);
+ }
+ // Only show the progress bars if the primary progress is not complete
+ if ((features & (1 << Window.FEATURE_PROGRESS)) != 0 &&
+ horizontalProgressBar.getProgress() < 10000) {
+ horizontalProgressBar.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void hideProgressBars(IcsProgressBar horizontalProgressBar, IcsProgressBar spinnyProgressBar) {
+ final int features = mFeatures;//getLocalFeatures();
+ Animation anim = AnimationUtils.loadAnimation(mActivity, android.R.anim.fade_out);
+ anim.setDuration(1000);
+ if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
+ spinnyProgressBar.getVisibility() == View.VISIBLE) {
+ spinnyProgressBar.startAnimation(anim);
+ spinnyProgressBar.setVisibility(View.INVISIBLE);
+ }
+ if ((features & (1 << Window.FEATURE_PROGRESS)) != 0 &&
+ horizontalProgressBar.getVisibility() == View.VISIBLE) {
+ horizontalProgressBar.startAnimation(anim);
+ horizontalProgressBar.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private IcsProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
+ if (mCircularProgressBar != null) {
+ return mCircularProgressBar;
+ }
+ if (mContentParent == null && shouldInstallDecor) {
+ installDecor();
+ }
+ mCircularProgressBar = (IcsProgressBar)mDecor.findViewById(R.id.abs__progress_circular);
+ if (mCircularProgressBar != null) {
+ mCircularProgressBar.setVisibility(View.INVISIBLE);
+ }
+ return mCircularProgressBar;
+ }
+
+ private IcsProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) {
+ if (mHorizontalProgressBar != null) {
+ return mHorizontalProgressBar;
+ }
+ if (mContentParent == null && shouldInstallDecor) {
+ installDecor();
+ }
+ mHorizontalProgressBar = (IcsProgressBar)mDecor.findViewById(R.id.abs__progress_horizontal);
+ if (mHorizontalProgressBar != null) {
+ mHorizontalProgressBar.setVisibility(View.INVISIBLE);
+ }
+ return mHorizontalProgressBar;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Feature management and content interaction and creation
+ ///////////////////////////////////////////////////////////////////////////
+
+ private int getFeatures() {
+ if (DEBUG) Log.d(TAG, "[getFeatures] returning " + mFeatures);
+
+ return mFeatures;
+ }
+
+ @Override
+ public boolean hasFeature(int featureId) {
+ if (DEBUG) Log.d(TAG, "[hasFeature] featureId: " + featureId);
+
+ boolean result = (mFeatures & (1 << featureId)) != 0;
+ if (DEBUG) Log.d(TAG, "[hasFeature] returning " + result);
+ return result;
+ }
+
+ @Override
+ public boolean requestFeature(int featureId) {
+ if (DEBUG) Log.d(TAG, "[requestFeature] featureId: " + featureId);
+
+ if (mContentParent != null) {
+ throw new AndroidRuntimeException("requestFeature() must be called before adding content");
+ }
+
+ switch (featureId) {
+ case Window.FEATURE_ACTION_BAR:
+ case Window.FEATURE_ACTION_BAR_OVERLAY:
+ case Window.FEATURE_ACTION_MODE_OVERLAY:
+ case Window.FEATURE_INDETERMINATE_PROGRESS:
+ case Window.FEATURE_NO_TITLE:
+ case Window.FEATURE_PROGRESS:
+ mFeatures |= (1 << featureId);
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public void setUiOptions(int uiOptions) {
+ if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions);
+
+ mUiOptions = uiOptions;
+ }
+
+ @Override
+ public void setUiOptions(int uiOptions, int mask) {
+ if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions + ", mask: " + mask);
+
+ mUiOptions = (mUiOptions & ~mask) | (uiOptions & mask);
+ }
+
+ @Override
+ public void setContentView(int layoutResId) {
+ if (DEBUG) Log.d(TAG, "[setContentView] layoutResId: " + layoutResId);
+
+ if (mContentParent == null) {
+ installDecor();
+ } else {
+ mContentParent.removeAllViews();
+ }
+ mActivity.getLayoutInflater().inflate(layoutResId, mContentParent);
+
+ android.view.Window.Callback callback = mActivity.getWindow().getCallback();
+ if (callback != null) {
+ callback.onContentChanged();
+ }
+
+ initActionBar();
+ }
+
+ @Override
+ public void setContentView(View view, ViewGroup.LayoutParams params) {
+ if (DEBUG) Log.d(TAG, "[setContentView] view: " + view + ", params: " + params);
+
+ if (mContentParent == null) {
+ installDecor();
+ } else {
+ mContentParent.removeAllViews();
+ }
+ mContentParent.addView(view, params);
+
+ android.view.Window.Callback callback = mActivity.getWindow().getCallback();
+ if (callback != null) {
+ callback.onContentChanged();
+ }
+
+ initActionBar();
+ }
+
+ @Override
+ public void addContentView(View view, ViewGroup.LayoutParams params) {
+ if (DEBUG) Log.d(TAG, "[addContentView] view: " + view + ", params: " + params);
+
+ if (mContentParent == null) {
+ installDecor();
+ }
+ mContentParent.addView(view, params);
+
+ initActionBar();
+ }
+
+ private void installDecor() {
+ if (DEBUG) Log.d(TAG, "[installDecor]");
+
+ if (mDecor == null) {
+ mDecor = (ViewGroup)mActivity.getWindow().getDecorView().findViewById(android.R.id.content);
+ }
+ if (mContentParent == null) {
+ //Since we are not operating at the window level we need to take
+ //into account the fact that the true decor may have already been
+ //initialized and had content attached to it. If that is the case,
+ //copy over its children to our new content container.
+ List<View> views = null;
+ if (mDecor.getChildCount() > 0) {
+ views = new ArrayList<View>(1); //Usually there's only one child
+ for (int i = 0, children = mDecor.getChildCount(); i < children; i++) {
+ View child = mDecor.getChildAt(0);
+ mDecor.removeView(child);
+ views.add(child);
+ }
+ }
+
+ mContentParent = generateLayout();
+
+ //Copy over the old children. See above for explanation.
+ if (views != null) {
+ for (View child : views) {
+ mContentParent.addView(child);
+ }
+ }
+
+ mTitleView = (TextView)mDecor.findViewById(android.R.id.title);
+ if (mTitleView != null) {
+ if (hasFeature(Window.FEATURE_NO_TITLE)) {
+ mTitleView.setVisibility(View.GONE);
+ if (mContentParent instanceof FrameLayout) {
+ ((FrameLayout)mContentParent).setForeground(null);
+ }
+ } else {
+ mTitleView.setText(mTitle);
+ }
+ } else {
+ wActionBar = (ActionBarView)mDecor.findViewById(R.id.abs__action_bar);
+ if (wActionBar != null) {
+ wActionBar.setWindowCallback(this);
+ if (wActionBar.getTitle() == null) {
+ wActionBar.setWindowTitle(mActivity.getTitle());
+ }
+ if (hasFeature(Window.FEATURE_PROGRESS)) {
+ wActionBar.initProgress();
+ }
+ if (hasFeature(Window.FEATURE_INDETERMINATE_PROGRESS)) {
+ wActionBar.initIndeterminateProgress();
+ }
+
+ //Since we don't require onCreate dispatching, parse for uiOptions here
+ int uiOptions = loadUiOptionsFromManifest(mActivity);
+ if (uiOptions != 0) {
+ mUiOptions = uiOptions;
+ }
+
+ boolean splitActionBar = false;
+ final boolean splitWhenNarrow = (mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0;
+ if (splitWhenNarrow) {
+ splitActionBar = getResources_getBoolean(mActivity, R.bool.abs__split_action_bar_is_narrow);
+ } else {
+ splitActionBar = mActivity.getTheme()
+ .obtainStyledAttributes(R.styleable.SherlockTheme)
+ .getBoolean(R.styleable.SherlockTheme_windowSplitActionBar, false);
+ }
+ final ActionBarContainer splitView = (ActionBarContainer)mDecor.findViewById(R.id.abs__split_action_bar);
+ if (splitView != null) {
+ wActionBar.setSplitView(splitView);
+ wActionBar.setSplitActionBar(splitActionBar);
+ wActionBar.setSplitWhenNarrow(splitWhenNarrow);
+
+ mActionModeView = (ActionBarContextView)mDecor.findViewById(R.id.abs__action_context_bar);
+ mActionModeView.setSplitView(splitView);
+ mActionModeView.setSplitActionBar(splitActionBar);
+ mActionModeView.setSplitWhenNarrow(splitWhenNarrow);
+ } else if (splitActionBar) {
+ Log.e(TAG, "Requested split action bar with incompatible window decor! Ignoring request.");
+ }
+
+ // Post the panel invalidate for later; avoid application onCreateOptionsMenu
+ // being called in the middle of onCreate or similar.
+ mDecor.post(new Runnable() {
+ @Override
+ public void run() {
+ //Invalidate if the panel menu hasn't been created before this.
+ if (!mIsDestroyed && !mActivity.isFinishing() && mMenu == null) {
+ dispatchInvalidateOptionsMenu();
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+
+ private ViewGroup generateLayout() {
+ if (DEBUG) Log.d(TAG, "[generateLayout]");
+
+ // Apply data from current theme.
+
+ TypedArray a = mActivity.getTheme().obtainStyledAttributes(R.styleable.SherlockTheme);
+
+ mIsFloating = a.getBoolean(R.styleable.SherlockTheme_android_windowIsFloating, false);
+
+ if (!a.hasValue(R.styleable.SherlockTheme_windowActionBar)) {
+ throw new IllegalStateException("You must use Theme.Sherlock, Theme.Sherlock.Light, Theme.Sherlock.Light.DarkActionBar, or a derivative.");
+ }
+
+ if (a.getBoolean(R.styleable.SherlockTheme_windowNoTitle, false)) {
+ requestFeature(Window.FEATURE_NO_TITLE);
+ } else if (a.getBoolean(R.styleable.SherlockTheme_windowActionBar, false)) {
+ // Don't allow an action bar if there is no title.
+ requestFeature(Window.FEATURE_ACTION_BAR);
+ }
+
+ if (a.getBoolean(R.styleable.SherlockTheme_windowActionBarOverlay, false)) {
+ requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+ }
+
+ if (a.getBoolean(R.styleable.SherlockTheme_windowActionModeOverlay, false)) {
+ requestFeature(Window.FEATURE_ACTION_MODE_OVERLAY);
+ }
+
+ a.recycle();
+
+ int layoutResource;
+ if (!hasFeature(Window.FEATURE_NO_TITLE)) {
+ if (mIsFloating) {
+ //Trash original dialog LinearLayout
+ mDecor = (ViewGroup)mDecor.getParent();
+ mDecor.removeAllViews();
+
+ layoutResource = R.layout.abs__dialog_title_holo;
+ } else {
+ if (hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) {
+ layoutResource = R.layout.abs__screen_action_bar_overlay;
+ } else {
+ layoutResource = R.layout.abs__screen_action_bar;
+ }
+ }
+ } else if (hasFeature(Window.FEATURE_ACTION_MODE_OVERLAY) && !hasFeature(Window.FEATURE_NO_TITLE)) {
+ layoutResource = R.layout.abs__screen_simple_overlay_action_mode;
+ } else {
+ layoutResource = R.layout.abs__screen_simple;
+ }
+
+ if (DEBUG) Log.d(TAG, "[generateLayout] using screen XML " + mActivity.getResources().getString(layoutResource));
+ View in = mActivity.getLayoutInflater().inflate(layoutResource, null);
+ mDecor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+
+ ViewGroup contentParent = (ViewGroup)mDecor.findViewById(R.id.abs__content);
+ if (contentParent == null) {
+ throw new RuntimeException("Couldn't find content container view");
+ }
+
+ //Make our new child the true content view (for fragments). VERY VOLATILE!
+ mDecor.setId(View.NO_ID);
+ contentParent.setId(android.R.id.content);
+
+ if (hasFeature(Window.FEATURE_INDETERMINATE_PROGRESS)) {
+ IcsProgressBar progress = getCircularProgressBar(false);
+ if (progress != null) {
+ progress.setIndeterminate(true);
+ }
+ }
+
+ return contentParent;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Miscellaneous
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Determine whether or not the device has a dedicated menu key.
+ *
+ * @return {@code true} if native menu key is present.
+ */
+ private boolean isReservingOverflow() {
+ if (!mReserveOverflowSet) {
+ mReserveOverflow = ActionMenuPresenter.reserveOverflow(mActivity);
+ mReserveOverflowSet = true;
+ }
+ return mReserveOverflow;
+ }
+
+ private static int loadUiOptionsFromManifest(Activity activity) {
+ int uiOptions = 0;
+ try {
+ final String thisPackage = activity.getClass().getName();
+ if (DEBUG) Log.i(TAG, "Parsing AndroidManifest.xml for " + thisPackage);
+
+ final String packageName = activity.getApplicationInfo().packageName;
+ final AssetManager am = activity.createPackageContext(packageName, 0).getAssets();
+ final XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml");
+
+ int eventType = xml.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ String name = xml.getName();
+
+ if ("application".equals(name)) {
+ //Check if the <application> has the attribute
+ if (DEBUG) Log.d(TAG, "Got <application>");
+
+ for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
+ if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
+
+ if ("uiOptions".equals(xml.getAttributeName(i))) {
+ uiOptions = xml.getAttributeIntValue(i, 0);
+ break; //out of for loop
+ }
+ }
+ } else if ("activity".equals(name)) {
+ //Check if the <activity> is us and has the attribute
+ if (DEBUG) Log.d(TAG, "Got <activity>");
+ Integer activityUiOptions = null;
+ String activityPackage = null;
+ boolean isOurActivity = false;
+
+ for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
+ if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
+
+ //We need both uiOptions and name attributes
+ String attrName = xml.getAttributeName(i);
+ if ("uiOptions".equals(attrName)) {
+ activityUiOptions = xml.getAttributeIntValue(i, 0);
+ } else if ("name".equals(attrName)) {
+ activityPackage = cleanActivityName(packageName, xml.getAttributeValue(i));
+ if (!thisPackage.equals(activityPackage)) {
+ break; //out of for loop
+ }
+ isOurActivity = true;
+ }
+
+ //Make sure we have both attributes before processing
+ if ((activityUiOptions != null) && (activityPackage != null)) {
+ //Our activity, uiOptions specified, override with our value
+ uiOptions = activityUiOptions.intValue();
+ }
+ }
+ if (isOurActivity) {
+ //If we matched our activity but it had no logo don't
+ //do any more processing of the manifest
+ break;
+ }
+ }
+ }
+ eventType = xml.nextToken();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (DEBUG) Log.i(TAG, "Returning " + Integer.toHexString(uiOptions));
+ return uiOptions;
+ }
+
+ public static String cleanActivityName(String manifestPackage, String activityName) {
+ if (activityName.charAt(0) == '.') {
+ //Relative activity name (e.g., android:name=".ui.SomeClass")
+ return manifestPackage + activityName;
+ }
+ if (activityName.indexOf('.', 1) == -1) {
+ //Unqualified activity name (e.g., android:name="SomeClass")
+ return manifestPackage + "." + activityName;
+ }
+ //Fully-qualified activity name (e.g., "com.my.package.SomeClass")
+ return activityName;
+ }
+
+ /**
+ * Clears out internal reference when the action mode is destroyed.
+ */
+ private class ActionModeCallbackWrapper implements ActionMode.Callback {
+ private final 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);
+ if (mActionModeView != null) {
+ mActionModeView.setVisibility(View.GONE);
+ mActionModeView.removeAllViews();
+ }
+ if (mActivity instanceof OnActionModeFinishedListener) {
+ ((OnActionModeFinishedListener)mActivity).onActionModeFinished(mActionMode);
+ }
+ mActionMode = null;
+ }
+ }
+}