Fix bug 2948913 - provide lifecycle notifications for action modes

Change-Id: I432e29a7bddb18bc32dfbe21a8ecd7d83158e3a0
diff --git a/api/current.xml b/api/current.xml
index 19c1384..d2bd8e5 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -21087,6 +21087,32 @@
 <parameter name="nonRoot" type="boolean">
 </parameter>
 </method>
+<method name="onActionModeFinished"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
+<method name="onActionModeStarted"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
 <method name="onActivityResult"
  return="void"
  abstract="false"
@@ -21722,19 +21748,6 @@
  visibility="protected"
 >
 </method>
-<method name="onStartActionMode"
- return="android.view.ActionMode"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="callback" type="android.view.ActionMode.Callback">
-</parameter>
-</method>
 <method name="onStop"
  return="void"
  abstract="false"
@@ -21835,6 +21848,19 @@
 <parameter name="hasFocus" type="boolean">
 </parameter>
 </method>
+<method name="onWindowStartingActionMode"
+ return="android.view.ActionMode"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.view.ActionMode.Callback">
+</parameter>
+</method>
 <method name="openContextMenu"
  return="void"
  abstract="false"
@@ -25434,6 +25460,32 @@
  visibility="public"
 >
 </method>
+<method name="onActionModeFinished"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
+<method name="onActionModeStarted"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
 <method name="onAttachedToWindow"
  return="void"
  abstract="false"
@@ -25784,19 +25836,6 @@
  visibility="protected"
 >
 </method>
-<method name="onStartActionMode"
- return="android.view.ActionMode"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="callback" type="android.view.ActionMode.Callback">
-</parameter>
-</method>
 <method name="onStop"
  return="void"
  abstract="false"
@@ -25860,6 +25899,19 @@
 <parameter name="hasFocus" type="boolean">
 </parameter>
 </method>
+<method name="onWindowStartingActionMode"
+ return="android.view.ActionMode"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.view.ActionMode.Callback">
+</parameter>
+</method>
 <method name="openContextMenu"
  return="void"
  abstract="false"
@@ -212083,6 +212135,32 @@
 <parameter name="event" type="android.view.MotionEvent">
 </parameter>
 </method>
+<method name="onActionModeFinished"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
+<method name="onActionModeStarted"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="android.view.ActionMode">
+</parameter>
+</method>
 <method name="onAttachedToWindow"
  return="void"
  abstract="true"
@@ -212217,19 +212295,6 @@
  visibility="public"
 >
 </method>
-<method name="onStartActionMode"
- return="android.view.ActionMode"
- abstract="true"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="callback" type="android.view.ActionMode.Callback">
-</parameter>
-</method>
 <method name="onWindowAttributesChanged"
  return="void"
  abstract="true"
@@ -212256,6 +212321,19 @@
 <parameter name="hasFocus" type="boolean">
 </parameter>
 </method>
+<method name="onWindowStartingActionMode"
+ return="android.view.ActionMode"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.view.ActionMode.Callback">
+</parameter>
+</method>
 </interface>
 <interface name="WindowManager"
  abstract="true"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 33f88d8..07d21fb 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4174,7 +4174,7 @@
     }
 
     /**
-     * Start a context mode.
+     * Start an action mode.
      *
      * @param callback Callback that will manage lifecycle events for this context mode
      * @return The ContextMode that was started, or null if it was canceled
@@ -4185,7 +4185,18 @@
         return mWindow.getDecorView().startActionMode(callback);
     }
 
-    public ActionMode onStartActionMode(ActionMode.Callback callback) {
+    /**
+     * Give the Activity a chance to control the UI for an action mode requested
+     * by the system.
+     *
+     * <p>Note: If you are looking for a notification callback that an action mode
+     * has been started for this activity, see {@link #onActionModeStarted(ActionMode)}.</p>
+     *
+     * @param callback The callback that should control the new action mode
+     * @return The new action mode, or <code>null</code> if the activity does not want to
+     *         provide special handling for this action mode. (It will be handled by the system.)
+     */
+    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
         initActionBar();
         if (mActionBar != null) {
             return mActionBar.startActionMode(callback);
@@ -4193,6 +4204,24 @@
         return null;
     }
 
+    /**
+     * Notifies the Activity that an action mode has been started.
+     * Activity subclasses overriding this method should call the superclass implementation.
+     *
+     * @param mode The new action mode.
+     */
+    public void onActionModeStarted(ActionMode mode) {
+    }
+
+    /**
+     * Notifies the activity that an action mode has finished.
+     * Activity subclasses overriding this method should call the superclass implementation.
+     *
+     * @param mode The action mode that just finished.
+     */
+    public void onActionModeFinished(ActionMode mode) {
+    }
+
     // ------------------ Internal API ------------------
     
     final void setParent(Activity parent) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 526129a..64a4d7a 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -867,13 +867,19 @@
         }
     }
 
-    public ActionMode onStartActionMode(ActionMode.Callback callback) {
+    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
         if (mActionBar != null) {
             return mActionBar.startActionMode(callback);
         }
         return null;
     }
 
+    public void onActionModeStarted(ActionMode mode) {
+    }
+
+    public void onActionModeFinished(ActionMode mode) {
+    }
+
     /**
      * @return The activity associated with this dialog, or null if there is no associated activity.
      */
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index d5d9a2e..5385cd9 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -313,12 +313,31 @@
         public boolean onSearchRequested();
 
         /**
-         * Called when an action mode is being started.
+         * 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
-         * @return The ActionMode that was started, or null if it was canceled
+         * @return The ActionMode that was started, or null if the system should present it
          */
-        public ActionMode onStartActionMode(ActionMode.Callback callback);
+        public ActionMode onWindowStartingActionMode(ActionMode.Callback callback);
+
+        /**
+         * Called when an action mode has been started. The appropriate mode callback
+         * method will have already been invoked.
+         *
+         * @param mode The new mode that has just been started.
+         */
+        public void onActionModeStarted(ActionMode mode);
+
+        /**
+         * Called when an action mode has been finished. The appropriate mode callback
+         * method will have already been invoked.
+         *
+         * @param mode The mode that was just finished.
+         */
+        public void onActionModeFinished(ActionMode mode);
     }
 
     public Window(Context context) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 3dd6510..bb39c8f 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1832,7 +1832,7 @@
             }
 
             final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
-            ActionMode mode = getCallback().onStartActionMode(wrappedCallback);
+            ActionMode mode = getCallback().onWindowStartingActionMode(wrappedCallback);
             if (mode != null) {
                 mActionMode = mode;
             } else {
@@ -1876,6 +1876,9 @@
                     }
                 }
             }
+            if (mActionMode != null) {
+                getCallback().onActionModeStarted(mActionMode);
+            }
             return mActionMode;
         }
 
@@ -2091,6 +2094,7 @@
                 if (mActionModeView != null) {
                     mActionModeView.removeAllViews();
                 }
+                getCallback().onActionModeFinished(mActionMode);
                 mActionMode = null;
             }
         }