Add callbacks to VoiceInteractionManagerService

Bug: 29582254

Change-Id: I548d01bd1c7e261b2d2e0afd606d964e5553124e
diff --git a/Android.mk b/Android.mk
index 044e45a..854f462 100644
--- a/Android.mk
+++ b/Android.mk
@@ -308,6 +308,7 @@
 	core/java/com/android/internal/app/IEphemeralResolver.aidl \
 	core/java/com/android/internal/app/ISoundTriggerService.aidl \
 	core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
+	core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl \
 	core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl \
 	core/java/com/android/internal/app/IVoiceInteractor.aidl \
 	core/java/com/android/internal/app/IVoiceInteractorCallback.aidl \
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index d552e54..56c5cc9 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -132,6 +132,16 @@
         }
     }
 
+    public void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener) {
+        try {
+            if (mVoiceInteractionManagerService != null) {
+                mVoiceInteractionManagerService.registerVoiceInteractionSessionListener(listener);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to register voice interaction listener", e);
+        }
+    }
+
     public ComponentName getAssistComponentForUser(int userId) {
         final String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
                 Settings.Secure.ASSISTANT, userId);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 1a963f3..033dd13 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -22,6 +22,7 @@
 
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.IVoiceInteractionSessionListener;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.SoundTrigger;
 import android.service.voice.IVoiceInteractionService;
@@ -136,4 +137,9 @@
      * Called when the lockscreen got shown.
      */
     void onLockscreenShown();
+
+    /**
+     * Register a voice interaction listener.
+     */
+    void registerVoiceInteractionSessionListener(IVoiceInteractionSessionListener listener);
 }
diff --git a/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
new file mode 100644
index 0000000..87749d2
--- /dev/null
+++ b/core/java/com/android/internal/app/IVoiceInteractionSessionListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package com.android.internal.app;
+
+ oneway interface IVoiceInteractionSessionListener {
+    /**
+     * Called when a voice session is shown.
+     */
+    void onVoiceSessionShown();
+
+    /**
+     * Called when a voice session is hidden.
+     */
+    void onVoiceSessionHidden();
+ }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index a5e771f..af2a286 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -15,6 +15,7 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -28,9 +29,9 @@
 import android.widget.ImageView;
 
 import com.android.internal.app.AssistUtils;
+import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
 
@@ -52,7 +53,7 @@
 
     private AssistOrbContainer mView;
     private final BaseStatusBar mBar;
-    private final AssistUtils mAssistUtils;
+    protected final AssistUtils mAssistUtils;
 
     private IVoiceInteractionSessionShowCallback mShowCallback =
             new IVoiceInteractionSessionShowCallback.Stub() {
@@ -82,6 +83,23 @@
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         mAssistUtils = new AssistUtils(context);
         mAssistDisclosure = new AssistDisclosure(context, new Handler());
+
+        registerVoiceInteractionSessionListener();
+    }
+
+    protected void registerVoiceInteractionSessionListener() {
+        mAssistUtils.registerVoiceInteractionSessionListener(
+                new IVoiceInteractionSessionListener.Stub() {
+            @Override
+            public void onVoiceSessionShown() throws RemoteException {
+                Log.v(TAG, "Voice open");
+            }
+
+            @Override
+            public void onVoiceSessionHidden() throws RemoteException {
+                Log.v(TAG, "Voice closed");
+            }
+        });
     }
 
     public void onConfigurationChanged() {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 23c58fe..794a73e 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -41,6 +41,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -55,15 +56,16 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.app.IVoiceInteractionManagerService;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
-import com.android.server.soundtrigger.SoundTriggerInternal;
 import com.android.server.SystemService;
 import com.android.server.UiThread;
+import com.android.server.soundtrigger.SoundTriggerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -1038,6 +1040,13 @@
         }
 
         @Override
+        public void registerVoiceInteractionSessionListener(
+                IVoiceInteractionSessionListener listener) {
+            enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
+            mImpl.registerVoiceInteractionSessionListener(listener);
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 3f9da4c..52e1a9b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -41,6 +42,7 @@
 import android.util.Slog;
 import android.view.IWindowManager;
 
+import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.server.LocalServices;
@@ -71,6 +73,9 @@
     VoiceInteractionSessionConnection mActiveSession;
     int mDisabledShowContext;
 
+    private final RemoteCallbackList<IVoiceInteractionSessionListener>
+            mVoiceInteractionSessionListeners = new RemoteCallbackList<>();
+
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -353,10 +358,52 @@
         }
     }
 
+    public void registerVoiceInteractionSessionListener(
+            IVoiceInteractionSessionListener listener) {
+        synchronized (mLock) {
+            mVoiceInteractionSessionListeners.register(listener);
+        }
+    }
+
     @Override
     public void sessionConnectionGone(VoiceInteractionSessionConnection connection) {
         synchronized (mLock) {
             finishLocked(connection.mToken, false);
         }
     }
+
+    @Override
+    public void onSessionShown(VoiceInteractionSessionConnection connection) {
+        synchronized (mLock) {
+            final int size = mVoiceInteractionSessionListeners.beginBroadcast();
+            for (int i = 0; i < size; ++i) {
+                final IVoiceInteractionSessionListener listener =
+                        mVoiceInteractionSessionListeners.getBroadcastItem(i);
+                try {
+                    listener.onVoiceSessionShown();
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error delivering voice interaction open event.", e);
+                }
+            }
+            mVoiceInteractionSessionListeners.finishBroadcast();
+        }
+    }
+
+    @Override
+    public void onSessionHidden(VoiceInteractionSessionConnection connection) {
+        synchronized (mLock) {
+            final int size = mVoiceInteractionSessionListeners.beginBroadcast();
+            for (int i = 0; i < size; ++i) {
+                final IVoiceInteractionSessionListener listener =
+                        mVoiceInteractionSessionListeners.getBroadcastItem(i);
+                try {
+                    listener.onVoiceSessionHidden();
+
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error delivering voice interaction closed event.", e);
+                }
+            }
+            mVoiceInteractionSessionListeners.finishBroadcast();
+        }
+    }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 0694911..b0cc2ac 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -130,6 +130,8 @@
 
     public interface Callback {
         public void sessionConnectionGone(VoiceInteractionSessionConnection connection);
+        public void onSessionShown(VoiceInteractionSessionConnection connection);
+        public void onSessionHidden(VoiceInteractionSessionConnection connection);
     }
 
     final ServiceConnection mFullConnection = new ServiceConnection() {
@@ -313,6 +315,7 @@
             } else if (showCallback != null) {
                 mPendingShowCallbacks.add(showCallback);
             }
+            mCallback.onSessionShown(this);
             return true;
         }
         if (showCallback != null) {
@@ -468,6 +471,7 @@
                     } catch (RemoteException e) {
                     }
                 }
+                mCallback.onSessionHidden(this);
             }
             if (mFullyBound) {
                 mContext.unbindService(mFullConnection);