Fix cleanup of voice sessions.

They would leave active voice activities lingering around.

Change-Id: I5b6716ab303636ebdf2f13c3172552a73dae3bb1
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 9e10e3d..1b2b08f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -319,6 +319,15 @@
             return true;
         }
 
+        case FINISH_VOICE_TASK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IVoiceInteractionSession session = IVoiceInteractionSession.Stub.asInterface(
+                    data.readStrongBinder());
+            finishVoiceTask(session);
+            reply.writeNoException();
+            return true;
+        }
+
         case WILL_ACTIVITY_BE_VISIBLE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -2468,6 +2477,16 @@
         reply.recycle();
         return res;
     }
+    public void finishVoiceTask(IVoiceInteractionSession session) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(session.asBinder());
+        mRemote.transact(FINISH_VOICE_TASK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
     public boolean willActivityBeVisible(IBinder token) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 01977fe..931903b 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -90,6 +90,7 @@
             throws RemoteException;
     public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException;
     public boolean finishActivityAffinity(IBinder token) throws RemoteException;
+    public void finishVoiceTask(IVoiceInteractionSession session) throws RemoteException;
     public boolean willActivityBeVisible(IBinder token) throws RemoteException;
     public Intent registerReceiver(IApplicationThread caller, String callerPackage,
             IIntentReceiver receiver, IntentFilter filter,
@@ -749,4 +750,5 @@
     int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
     int START_LOCK_TASK_BY_CURRENT = IBinder.FIRST_CALL_TRANSACTION+221;
     int STOP_LOCK_TASK_BY_CURRENT = IBinder.FIRST_CALL_TRANSACTION+222;
+    int FINISH_VOICE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+223;
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 12f406f..6474047 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3892,6 +3892,19 @@
     }
 
     @Override
+    public void finishVoiceTask(IVoiceInteractionSession session) {
+        synchronized(this) {
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                mStackSupervisor.finishVoiceTask(session);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+
+    }
+
+    @Override
     public boolean willActivityBeVisible(IBinder token) {
         synchronized(this) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 5442f83..545423b 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2497,6 +2497,27 @@
         }
     }
 
+    final void finishVoiceTask(IVoiceInteractionSession session) {
+        IBinder sessionBinder = session.asBinder();
+        boolean didOne = false;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            TaskRecord tr = mTaskHistory.get(taskNdx);
+            if (tr.voiceSession != null && tr.voiceSession.asBinder() == sessionBinder) {
+                for (int activityNdx = tr.mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
+                    ActivityRecord r = tr.mActivities.get(activityNdx);
+                    if (!r.finishing) {
+                        finishActivityLocked(r, Activity.RESULT_CANCELED, null, "finish-voice",
+                                false);
+                        didOne = true;
+                    }
+                }
+            }
+        }
+        if (didOne) {
+            mService.updateOomAdjLocked();
+        }
+    }
+
     final boolean finishActivityAffinityLocked(ActivityRecord r) {
         ArrayList<ActivityRecord> activities = r.task.mActivities;
         for (int index = activities.indexOf(r); index >= 0; --index) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 15bae9b..c4423de 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2256,6 +2256,17 @@
         }
     }
 
+    void finishVoiceTask(IVoiceInteractionSession session) {
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.finishVoiceTask(session);
+            }
+        }
+    }
+
     void findTaskToMoveToFrontLocked(TaskRecord task, int flags, Bundle options) {
         if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
             mUserLeaving = true;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 62ff121..8d96fb3 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -150,6 +150,12 @@
                         Slog.w(TAG, "Voice interation session already dead");
                     }
                 }
+                if (mSession != null) {
+                    try {
+                        mAm.finishVoiceTask(mSession);
+                    } catch (RemoteException e) {
+                    }
+                }
                 mContext.unbindService(this);
                 try {
                     mIWindowManager.removeWindowToken(mToken);