diff options
| author | Clara Bayarri <clarabayarri@google.com> | 2015-03-02 19:42:48 +0000 |
|---|---|---|
| committer | Clara Bayarri <clarabayarri@google.com> | 2015-03-13 10:51:51 +0000 |
| commit | 4423d91de5300d3fd318bf5bc2d4d7e5bb856abf (patch) | |
| tree | f62a9d12f773379d306278c6cb003f545df8138c | |
| parent | 993d128477bf7c9a55a015bd9dc5e4fafddf9a14 (diff) | |
| download | frameworks_base-4423d91de5300d3fd318bf5bc2d4d7e5bb856abf.zip frameworks_base-4423d91de5300d3fd318bf5bc2d4d7e5bb856abf.tar.gz frameworks_base-4423d91de5300d3fd318bf5bc2d4d7e5bb856abf.tar.bz2 | |
Add a type parameter to startActionMode() calls.
This requires adding a new method to View and Window.Callback to pass
down the type as a parameter.
For compatibility purposes, the new method implementations keep the
type and call the old method, in case clients have subclassed it.
Change-Id: If5d857f131e33be8cc6a8814f2e9c4e85ad2da25
| -rw-r--r-- | api/current.txt | 8 | ||||
| -rw-r--r-- | api/system-current.txt | 8 | ||||
| -rw-r--r-- | core/java/android/app/Activity.java | 44 | ||||
| -rw-r--r-- | core/java/android/app/Dialog.java | 25 | ||||
| -rw-r--r-- | core/java/android/app/SearchDialog.java | 6 | ||||
| -rw-r--r-- | core/java/android/service/dreams/DreamService.java | 7 | ||||
| -rw-r--r-- | core/java/android/view/PhoneWindow.java | 177 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 23 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 117 | ||||
| -rw-r--r-- | core/java/android/view/ViewParent.java | 23 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 6 | ||||
| -rw-r--r-- | core/java/android/view/Window.java | 17 | ||||
| -rw-r--r-- | core/java/android/view/WindowCallbackWrapper.java | 5 | ||||
| -rw-r--r-- | core/java/com/android/internal/app/WindowDecorActionBar.java | 40 | ||||
| -rw-r--r-- | core/java/com/android/internal/view/StandaloneActionMode.java | 7 | ||||
| -rw-r--r-- | core/java/com/android/internal/widget/ActionBarContainer.java | 9 | ||||
| -rw-r--r-- | tools/layoutlib/bridge/src/android/view/WindowCallback.java | 5 |
17 files changed, 395 insertions, 132 deletions
diff --git a/api/current.txt b/api/current.txt index 16eb4e9..5f36806 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3450,6 +3450,7 @@ package android.app { method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); method public void onWindowFocusChanged(boolean); method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); method public void openContextMenu(android.view.View); method public void openOptionsMenu(); method public void overridePendingTransition(int, int); @@ -3496,6 +3497,7 @@ package android.app { method public final deprecated void showDialog(int); method public final deprecated boolean showDialog(int, android.os.Bundle); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int); method public void startActivityForResult(android.content.Intent, int); method public void startActivityForResult(android.content.Intent, int, android.os.Bundle); method public void startActivityFromChild(android.app.Activity, android.content.Intent, int); @@ -4073,6 +4075,7 @@ package android.app { method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); method public void onWindowFocusChanged(boolean); method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); method public void openContextMenu(android.view.View); method public void openOptionsMenu(); method public void registerForContextMenu(android.view.View); @@ -27541,6 +27544,7 @@ package android.service.dreams { method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); method public void onWindowFocusChanged(boolean); method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); method public void setContentView(int); method public void setContentView(android.view.View); method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams); @@ -34470,6 +34474,7 @@ package android.view { method public void setZ(float); method public boolean showContextMenu(); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int); method public void startAnimation(android.view.animation.Animation); method public final boolean startDrag(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int); method public boolean startNestedScroll(int); @@ -34925,6 +34930,7 @@ package android.view { method public boolean shouldDelayChildPressedState(); method public boolean showContextMenuForChild(android.view.View); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); + method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); method public void startLayoutAnimation(); method public void startViewTransition(android.view.View); method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams); @@ -35045,6 +35051,7 @@ package android.view { method public abstract void requestTransparentRegion(android.view.View); method public abstract boolean showContextMenuForChild(android.view.View); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); + method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); } public class ViewPropertyAnimator { @@ -35333,6 +35340,7 @@ package android.view { method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); method public abstract void onWindowFocusChanged(boolean); method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); + method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); } public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable { diff --git a/api/system-current.txt b/api/system-current.txt index 1707897..2cb56ea 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3533,6 +3533,7 @@ package android.app { method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); method public void onWindowFocusChanged(boolean); method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); method public void openContextMenu(android.view.View); method public void openOptionsMenu(); method public void overridePendingTransition(int, int); @@ -3579,6 +3580,7 @@ package android.app { method public final deprecated void showDialog(int); method public final deprecated boolean showDialog(int, android.os.Bundle); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int); method public void startActivityForResult(android.content.Intent, int); method public void startActivityForResult(android.content.Intent, int, android.os.Bundle); method public void startActivityFromChild(android.app.Activity, android.content.Intent, int); @@ -4163,6 +4165,7 @@ package android.app { method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); method public void onWindowFocusChanged(boolean); method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); method public void openContextMenu(android.view.View); method public void openOptionsMenu(); method public void registerForContextMenu(android.view.View); @@ -29147,6 +29150,7 @@ package android.service.dreams { method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); method public void onWindowFocusChanged(boolean); method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); method public void setContentView(int); method public void setContentView(android.view.View); method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams); @@ -36638,6 +36642,7 @@ package android.view { method public void setZ(float); method public boolean showContextMenu(); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback); + method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int); method public void startAnimation(android.view.animation.Animation); method public final boolean startDrag(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int); method public boolean startNestedScroll(int); @@ -37093,6 +37098,7 @@ package android.view { method public boolean shouldDelayChildPressedState(); method public boolean showContextMenuForChild(android.view.View); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); + method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); method public void startLayoutAnimation(); method public void startViewTransition(android.view.View); method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams); @@ -37213,6 +37219,7 @@ package android.view { method public abstract void requestTransparentRegion(android.view.View); method public abstract boolean showContextMenuForChild(android.view.View); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); + method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); } public class ViewPropertyAnimator { @@ -37502,6 +37509,7 @@ package android.view { method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams); method public abstract void onWindowFocusChanged(boolean); method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); + method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); } public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable { diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 9f8befe..fdbf197 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -787,6 +787,7 @@ public class Activity extends ContextThemeWrapper private boolean mChangeCanvasToTranslucent; private boolean mTitleReady = false; + private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY; private int mDefaultKeyMode = DEFAULT_KEYS_DISABLE; private SpannableStringBuilder mDefaultKeySsb = null; @@ -5681,10 +5682,10 @@ public class Activity extends ContextThemeWrapper } /** - * Start an action mode. + * Start an action mode of the default type {@link ActionMode#TYPE_PRIMARY}. * - * @param callback Callback that will manage lifecycle events for this context mode - * @return The ContextMode that was started, or null if it was canceled + * @param callback Callback that will manage lifecycle events for this action mode + * @return The ActionMode that was started, or null if it was canceled * * @see ActionMode */ @@ -5694,6 +5695,20 @@ public class Activity extends ContextThemeWrapper } /** + * Start an action mode of the given type. + * + * @param callback Callback that will manage lifecycle events for this action mode + * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. + * @return The ActionMode that was started, or null if it was canceled + * + * @see ActionMode + */ + @Nullable + public ActionMode startActionMode(ActionMode.Callback callback, int type) { + return mWindow.getDecorView().startActionMode(callback, type); + } + + /** * Give the Activity a chance to control the UI for an action mode requested * by the system. * @@ -5707,14 +5722,31 @@ public class Activity extends ContextThemeWrapper @Nullable @Override public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { - initWindowDecorActionBar(); - if (mActionBar != null) { - return mActionBar.startActionMode(callback); + // Only Primary ActionModes are represented in the ActionBar. + if (mActionModeTypeStarting == ActionMode.TYPE_PRIMARY) { + initWindowDecorActionBar(); + if (mActionBar != null) { + return mActionBar.startActionMode(callback); + } } return null; } /** + * {@inheritDoc} + */ + @Nullable + @Override + public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) { + try { + mActionModeTypeStarting = type; + return onWindowStartingActionMode(callback); + } finally { + mActionModeTypeStarting = ActionMode.TYPE_PRIMARY; + } + } + + /** * Notifies the Activity that an action mode has been started. * Activity subclasses overriding this method should call the superclass implementation. * diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 8e64b34..9defcbe 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -121,6 +121,8 @@ public class Dialog implements DialogInterface, Window.Callback, private ActionMode mActionMode; + private int mActionModeTypeStarting = ActionMode.TYPE_PRIMARY; + private final Runnable mDismissAction = new Runnable() { public void run() { dismissDialog(); @@ -973,13 +975,13 @@ public class Dialog implements DialogInterface, Window.Callback, public boolean onContextItemSelected(MenuItem item) { return false; } - + /** * @see Activity#onContextMenuClosed(Menu) */ public void onContextMenuClosed(Menu menu) { } - + /** * This hook is called when the user signals the desire to start a search. */ @@ -998,8 +1000,12 @@ public class Dialog implements DialogInterface, Window.Callback, } } + /** + * {@inheritDoc} + */ + @Override public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { - if (mActionBar != null) { + if (mActionBar != null && mActionModeTypeStarting == ActionMode.TYPE_PRIMARY) { return mActionBar.startActionMode(callback); } return null; @@ -1007,6 +1013,19 @@ public class Dialog implements DialogInterface, Window.Callback, /** * {@inheritDoc} + */ + @Override + public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) { + try { + mActionModeTypeStarting = type; + return onWindowStartingActionMode(callback); + } finally { + mActionModeTypeStarting = ActionMode.TYPE_PRIMARY; + } + } + + /** + * {@inheritDoc} * * Note that if you override this method you should always call through * to the superclass implementation by calling super.onActionModeStarted(mode). diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index af1810b..c719a0e 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -639,6 +639,12 @@ public class SearchDialog extends Dialog { public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) { return null; } + + @Override + public ActionMode startActionModeForChild( + View child, ActionMode.Callback callback, int type) { + return null; + } } private boolean isEmpty(AutoCompleteTextView actv) { diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index df4d7e0..822bfcc 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -344,6 +344,13 @@ public class DreamService extends Service implements Window.Callback { /** {@inheritDoc} */ @Override + public ActionMode onWindowStartingActionMode( + android.view.ActionMode.Callback callback, int type) { + return null; + } + + /** {@inheritDoc} */ + @Override public void onActionModeStarted(ActionMode mode) { } diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java index d4b14f6..e43dfef 100644 --- a/core/java/android/view/PhoneWindow.java +++ b/core/java/android/view/PhoneWindow.java @@ -28,7 +28,6 @@ import android.app.SearchManager; import android.os.UserHandle; import com.android.internal.R; -import com.android.internal.view.ActionModeWrapper; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; import com.android.internal.view.menu.ContextMenuBuilder; @@ -76,7 +75,6 @@ import android.util.EventLog; import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; -import android.view.ActionMode.Callback; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.Animation; @@ -2676,44 +2674,47 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override + public ActionMode startActionModeForChild( + View child, ActionMode.Callback callback, int type) { + // originalView can be used here to be sure that we don't obscure + // relevant content with the context mode UI. + return startActionMode(callback, type); + } + + @Override public ActionMode startActionMode(ActionMode.Callback callback) { + return startActionMode(callback, ActionMode.TYPE_PRIMARY); + } + + @Override + public ActionMode startActionMode(ActionMode.Callback callback, int type) { if (mActionMode != null) { mActionMode.finish(); mActionMode = null; } - ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback); - ActionModeWrapper mode = null; - ActionMode callbackMode = null; + ActionMode mode = null; if (getCallback() != null && !isDestroyed()) { try { - callbackMode = - getCallback().onWindowStartingActionMode(wrappedCallback); - if (callbackMode != null && callbackMode instanceof ActionModeWrapper) { - // If we get an ActionModeWrapper back, we handle its lifecycle. - mode = (ActionModeWrapper) callbackMode; - callbackMode = null; - } + mode = getCallback().onWindowStartingActionMode(wrappedCallback, type); } catch (AbstractMethodError ame) { // Older apps might not implement this callback method. } } - if (callbackMode != null) { - mActionMode = callbackMode; + if (mode != null) { + mActionMode = mode; } else { - if (mode == null) { - mode = new ActionModeWrapper( - mContext, wrappedCallback, new StandaloneActionModeProvider()); - } - if (mActionModeView != null) { - mActionModeView.killMode(); - } - if (callback.onCreateActionMode(mode, mode.getMenu())) { - mode.lockType(); - mActionMode = mode.getWrappedActionMode(); - mActionMode.invalidate(); - } else { - mActionMode = null; + if (type == ActionMode.TYPE_PRIMARY) { + if (mActionModeView != null) { + mActionModeView.killMode(); + } + mode = createStandaloneActionMode(wrappedCallback); + if (mode != null && callback.onCreateActionMode(mode, mode.getMenu())) { + mActionMode = mode; + mActionMode.invalidate(); + } else { + mActionMode = null; + } } } if (mActionMode != null && getCallback() != null && !isDestroyed()) { @@ -3209,80 +3210,70 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { updateColorViewTranslations(); } - /** - * Encapsulates the view creation for {@link StandaloneActionMode}. - */ - private class StandaloneActionModeProvider - implements ActionModeWrapper.ActionModeProvider { + private ActionMode createStandaloneActionMode(ActionMode.Callback callback) { + if (mActionModeView == null) { + if (isFloating()) { + // Use the action bar theme. + final TypedValue outValue = new TypedValue(); + final Theme baseTheme = mContext.getTheme(); + baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true); - @Override - public ActionMode createActionMode(android.view.ActionMode.Callback callback, - MenuBuilder menuBuilder) { - if (mActionModeView == null) { - if (isFloating()) { - // Use the action bar theme. - final TypedValue outValue = new TypedValue(); - final Theme baseTheme = mContext.getTheme(); - baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true); - - final Context actionBarContext; - if (outValue.resourceId != 0) { - final Theme actionBarTheme = mContext.getResources().newTheme(); - actionBarTheme.setTo(baseTheme); - actionBarTheme.applyStyle(outValue.resourceId, true); - - actionBarContext = new ContextThemeWrapper(mContext, 0); - actionBarContext.getTheme().setTo(actionBarTheme); - } else { - actionBarContext = mContext; - } + final Context actionBarContext; + if (outValue.resourceId != 0) { + final Theme actionBarTheme = mContext.getResources().newTheme(); + actionBarTheme.setTo(baseTheme); + actionBarTheme.applyStyle(outValue.resourceId, true); - mActionModeView = new ActionBarContextView(actionBarContext); - mActionModePopup = new PopupWindow(actionBarContext, null, - R.attr.actionModePopupWindowStyle); - mActionModePopup.setWindowLayoutType( - WindowManager.LayoutParams.TYPE_APPLICATION); - mActionModePopup.setContentView(mActionModeView); - mActionModePopup.setWidth(MATCH_PARENT); - - actionBarContext.getTheme().resolveAttribute( - R.attr.actionBarSize, outValue, true); - final int height = TypedValue.complexToDimensionPixelSize(outValue.data, - actionBarContext.getResources().getDisplayMetrics()); - mActionModeView.setContentHeight(height); - mActionModePopup.setHeight(WRAP_CONTENT); - mShowActionModePopup = new Runnable() { - public void run() { - mActionModePopup.showAtLocation( - mActionModeView.getApplicationWindowToken(), - Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0); - } - }; + actionBarContext = new ContextThemeWrapper(mContext, 0); + actionBarContext.getTheme().setTo(actionBarTheme); } else { - ViewStub stub = (ViewStub) findViewById( - R.id.action_mode_bar_stub); - if (stub != null) { - mActionModeView = (ActionBarContextView) stub.inflate(); + actionBarContext = mContext; + } + + mActionModeView = new ActionBarContextView(actionBarContext); + mActionModePopup = new PopupWindow(actionBarContext, null, + R.attr.actionModePopupWindowStyle); + mActionModePopup.setWindowLayoutType( + WindowManager.LayoutParams.TYPE_APPLICATION); + mActionModePopup.setContentView(mActionModeView); + mActionModePopup.setWidth(MATCH_PARENT); + + actionBarContext.getTheme().resolveAttribute( + R.attr.actionBarSize, outValue, true); + final int height = TypedValue.complexToDimensionPixelSize(outValue.data, + actionBarContext.getResources().getDisplayMetrics()); + mActionModeView.setContentHeight(height); + mActionModePopup.setHeight(WRAP_CONTENT); + mShowActionModePopup = new Runnable() { + public void run() { + mActionModePopup.showAtLocation( + mActionModeView.getApplicationWindowToken(), + Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0); } + }; + } else { + ViewStub stub = (ViewStub) findViewById( + R.id.action_mode_bar_stub); + if (stub != null) { + mActionModeView = (ActionBarContextView) stub.inflate(); } } - if (mActionModeView != null) { - ActionMode mode = new StandaloneActionMode( - mActionModeView.getContext(), mActionModeView, - callback, mActionModePopup == null, menuBuilder); - mActionModeView.killMode(); - mActionModeView.initForMode(mode); - mActionModeView.setVisibility(View.VISIBLE); - if (mActionModePopup != null) { - post(mShowActionModePopup); - } - mActionModeView.sendAccessibilityEvent( - AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); - return mode; + } + if (mActionModeView != null) { + ActionMode mode = new StandaloneActionMode( + mActionModeView.getContext(), mActionModeView, + callback, mActionModePopup == null); + mActionModeView.killMode(); + mActionModeView.initForMode(mode); + mActionModeView.setVisibility(View.VISIBLE); + if (mActionModePopup != null) { + post(mShowActionModePopup); } - return null; + mActionModeView.sendAccessibilityEvent( + AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + return mode; } - + return null; } /** diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4f2d4a6..57dc015 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4844,17 +4844,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** - * Start an action mode. + * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. * * @param callback Callback that will control the lifecycle of the action mode * @return The new action mode if it is started, null otherwise * * @see ActionMode + * @see #startActionMode(android.view.ActionMode.Callback, int) */ public ActionMode startActionMode(ActionMode.Callback callback) { + return startActionMode(callback, ActionMode.TYPE_PRIMARY); + } + + /** + * Start an action mode with the given type. + * + * @param callback Callback that will control the lifecycle of the action mode + * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. + * @return The new action mode if it is started, null otherwise + * + * @see ActionMode + */ + public ActionMode startActionMode(ActionMode.Callback callback, int type) { ViewParent parent = getParent(); if (parent == null) return null; - return parent.startActionModeForChild(this, callback); + try { + return parent.startActionModeForChild(this, callback, type); + } catch (AbstractMethodError ame) { + // Older implementations of custom views might not implement this. + return parent.startActionModeForChild(this, callback); + } } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index dfe9f0e..87f3e94 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -369,6 +369,26 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000; /** + * When true, indicates that a call to startActionModeForChild was made with the type parameter + * and should not be ignored. This helps in backwards compatibility with the existing method + * without a type. + * + * @see #startActionModeForChild(View, android.view.ActionMode.Callback) + * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int) + */ + private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED = 0x8000000; + + /** + * When true, indicates that a call to startActionModeForChild was made without the type + * parameter. This helps in backwards compatibility with the existing method + * without a type. + * + * @see #startActionModeForChild(View, android.view.ActionMode.Callback) + * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int) + */ + private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED = 0x10000000; + + /** * Indicates which types of drawing caches are to be kept in memory. * This field should be made private, so it is hidden from the SDK. * {@hide} @@ -479,6 +499,60 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ private int mNestedScrollAxes; + /** + * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild. + * + * @see #startActionModeForChild(View, android.view.ActionMode.Callback) + * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int) + */ + private static final ActionMode SENTINEL_ACTION_MODE = new ActionMode() { + @Override + public void setTitle(CharSequence title) {} + + @Override + public void setTitle(int resId) {} + + @Override + public void setSubtitle(CharSequence subtitle) {} + + @Override + public void setSubtitle(int resId) {} + + @Override + public void setCustomView(View view) {} + + @Override + public void invalidate() {} + + @Override + public void finish() {} + + @Override + public Menu getMenu() { + return null; + } + + @Override + public CharSequence getTitle() { + return null; + } + + @Override + public CharSequence getSubtitle() { + return null; + } + + @Override + public View getCustomView() { + return null; + } + + @Override + public MenuInflater getMenuInflater() { + return null; + } + }; + public ViewGroup(Context context) { this(context, null); } @@ -694,8 +768,49 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * {@inheritDoc} */ + @Override public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { - return mParent != null ? mParent.startActionModeForChild(originalView, callback) : null; + if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) { + // This is the original call. + try { + mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED; + return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY); + } finally { + mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED; + } + } else { + // We are being called from the new method with type. + return SENTINEL_ACTION_MODE; + } + } + + /** + * {@inheritDoc} + */ + @Override + public ActionMode startActionModeForChild( + View originalView, ActionMode.Callback callback, int type) { + if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0) { + ActionMode mode; + try { + mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED; + mode = startActionModeForChild(originalView, callback); + } finally { + mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED; + } + if (mode != SENTINEL_ACTION_MODE) { + return mode; + } + } + if (mParent != null) { + try { + return mParent.startActionModeForChild(originalView, callback, type); + } catch (AbstractMethodError ame) { + // Custom view parents might not implement this method. + return mParent.startActionModeForChild(originalView, callback); + } + } + return null; } /** diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index 035871d..15b86d1 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -190,7 +190,8 @@ public interface ViewParent { public void createContextMenu(ContextMenu menu); /** - * Start an action mode for the specified view. + * Start an action mode for the specified view with the default type + * {@link ActionMode#TYPE_PRIMARY}. * * <p>In most cases, a subclass does not need to override this. However, if the * subclass is added directly to the window manager (for example, @@ -200,17 +201,35 @@ public interface ViewParent { * @param originalView The source view where the action mode was first invoked * @param callback The callback that will handle lifecycle events for the action mode * @return The new action mode if it was started, null otherwise + * + * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int) */ public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback); /** + * Start an action mode of a specific type for the specified view. + * + * <p>In most cases, a subclass does not need to override this. However, if the + * subclass is added directly to the window manager (for example, + * {@link ViewManager#addView(View, android.view.ViewGroup.LayoutParams)}) + * then it should override this and start the action mode.</p> + * + * @param originalView The source view where the action mode was first invoked + * @param callback The callback that will handle lifecycle events for the action mode + * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. + * @return The new action mode if it was started, null otherwise + */ + public ActionMode startActionModeForChild( + View originalView, ActionMode.Callback callback, int type); + + /** * This method is called on the parent when a child's drawable state * has changed. * * @param child The child whose drawable state has changed. */ public void childDrawableStateChanged(View child); - + /** * Called when a child does not want this parent and its ancestors to * intercept touch events with diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index f970e88..1473806 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6227,6 +6227,12 @@ public final class ViewRootImpl implements ViewParent, } @Override + public ActionMode startActionModeForChild( + View originalView, ActionMode.Callback callback, int type) { + return null; + } + + @Override public void createContextMenu(ContextMenu menu) { } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 744f665..f36fd5a 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -416,7 +416,9 @@ public abstract class Window { * Called when an action mode is being started for this window. Gives the * callback an opportunity to handle the action mode in its own unique and * beautiful way. If this method returns null the system can choose a way - * to present the mode or choose not to start the mode at all. + * to present the mode or choose not to start the mode at all. This is equivalent + * to {@link #onWindowStartingActionMode(android.view.ActionMode.Callback, int)} + * with type {@link ActionMode#TYPE_PRIMARY}. * * @param callback Callback to control the lifecycle of this action mode * @return The ActionMode that was started, or null if the system should present it @@ -425,6 +427,19 @@ public abstract class Window { public ActionMode onWindowStartingActionMode(ActionMode.Callback callback); /** + * Called when an action mode is being started for this window. Gives the + * callback an opportunity to handle the action mode in its own unique and + * beautiful way. If this method returns null the system can choose a way + * to present the mode or choose not to start the mode at all. + * + * @param callback Callback to control the lifecycle of this action mode + * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. + * @return The ActionMode that was started, or null if the system should present it + */ + @Nullable + public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type); + + /** * Called when an action mode has been started. The appropriate mode callback * method will have already been invoked. * diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java index 35a6a76..979ee95 100644 --- a/core/java/android/view/WindowCallbackWrapper.java +++ b/core/java/android/view/WindowCallbackWrapper.java @@ -132,6 +132,11 @@ public class WindowCallbackWrapper implements Window.Callback { } @Override + public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int type) { + return mWrapped.onWindowStartingActionMode(callback, type); + } + + @Override public void onActionModeStarted(ActionMode mode) { mWrapped.onActionModeStarted(mode); } diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java index 70a0b6b..2bf02f1 100644 --- a/core/java/com/android/internal/app/WindowDecorActionBar.java +++ b/core/java/com/android/internal/app/WindowDecorActionBar.java @@ -493,21 +493,15 @@ public class WindowDecorActionBar extends ActionBar implements } public ActionMode startActionMode(ActionMode.Callback callback) { - return new ActionModeWrapper(mContext, callback, new ActionModeProviderImpl()); - } - - private class ActionModeProviderImpl implements ActionModeWrapper.ActionModeProvider { - - @Override - public ActionMode createActionMode(Callback callback, MenuBuilder menuBuilder) { - if (mActionMode != null) { - mActionMode.finish(); - } + if (mActionMode != null) { + mActionMode.finish(); + } - mOverlayLayout.setHideOnContentScrollEnabled(false); - mContextView.killMode(); - ActionModeImpl mode = new ActionModeImpl( - mContextView.getContext(), callback, menuBuilder); + mOverlayLayout.setHideOnContentScrollEnabled(false); + mContextView.killMode(); + ActionModeImpl mode = new ActionModeImpl(mContextView.getContext(), callback); + if (mode.dispatchOnCreate()) { + mode.invalidate(); mContextView.initForMode(mode); animateToMode(true); if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { @@ -523,6 +517,7 @@ public class WindowDecorActionBar extends ActionBar implements mActionMode = mode; return mode; } + return null; } private void configureTab(Tab tab, int position) { @@ -951,13 +946,11 @@ public class WindowDecorActionBar extends ActionBar implements private WeakReference<View> mCustomView; public ActionModeImpl( - Context context, ActionMode.Callback callback, MenuBuilder menuBuilder) { + Context context, ActionMode.Callback callback) { mActionModeContext = context; mCallback = callback; - mMenu = menuBuilder == null - ? new MenuBuilder(context) - .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) - : menuBuilder; + mMenu = new MenuBuilder(context) + .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); mMenu.setCallback(this); } @@ -1019,6 +1012,15 @@ public class WindowDecorActionBar extends ActionBar implements } } + public boolean dispatchOnCreate() { + mMenu.stopDispatchingItemsChanged(); + try { + return mCallback.onCreateActionMode(this, mMenu); + } finally { + mMenu.startDispatchingItemsChanged(); + } + } + @Override public void setCustomView(View view) { mContextView.setCustomView(view); diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java index 2812b77..e6d911c 100644 --- a/core/java/com/android/internal/view/StandaloneActionMode.java +++ b/core/java/com/android/internal/view/StandaloneActionMode.java @@ -20,7 +20,6 @@ import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.SubMenuBuilder; import com.android.internal.widget.ActionBarContextView; -import android.annotation.Nullable; import android.content.Context; import android.view.ActionMode; import android.view.Menu; @@ -42,14 +41,12 @@ public class StandaloneActionMode extends ActionMode implements MenuBuilder.Call private MenuBuilder mMenu; public StandaloneActionMode(Context context, ActionBarContextView view, - ActionMode.Callback callback, boolean isFocusable, @Nullable MenuBuilder menuBuilder) { + ActionMode.Callback callback, boolean isFocusable) { mContext = context; mContextView = view; mCallback = callback; - mMenu = (menuBuilder != null) - ? menuBuilder - : new MenuBuilder(view.getContext()).setDefaultShowAsAction( + mMenu = new MenuBuilder(view.getContext()).setDefaultShowAsAction( MenuItem.SHOW_AS_ACTION_IF_ROOM); mMenu.setCallback(this); mFocusable = isFocusable; diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java index eaf0bbc..a5efa82 100644 --- a/core/java/com/android/internal/widget/ActionBarContainer.java +++ b/core/java/com/android/internal/widget/ActionBarContainer.java @@ -256,6 +256,15 @@ public class ActionBarContainer extends FrameLayout { return null; } + @Override + public ActionMode startActionModeForChild( + View child, ActionMode.Callback callback, int type) { + if (type != ActionMode.TYPE_PRIMARY) { + return super.startActionModeForChild(child, callback, type); + } + return null; + } + private static boolean isCollapsed(View view) { return view == null || view.getVisibility() == GONE || view.getMeasuredHeight() == 0; } diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java index 78242a8..823b247 100644 --- a/tools/layoutlib/bridge/src/android/view/WindowCallback.java +++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java @@ -120,6 +120,11 @@ public class WindowCallback implements Window.Callback { } @Override + public ActionMode onWindowStartingActionMode(Callback callback, int type) { + return null; + } + + @Override public void onActionModeStarted(ActionMode mode) { } |
