Fix issue #20672970: Notifications are not dismissed on hot word detection

Add new VoiceInteractionSession.closeSystemDialogs() API that closes
everything except the session itself.

Change-Id: If45f1e120d8ca095b6c8055b6485acb5e710820e
diff --git a/api/current.txt b/api/current.txt
index 3ae5372..61a952c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28807,6 +28807,7 @@
   public class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
+    method public void closeSystemDialogs();
     method public void finish();
     method public android.content.Context getContext();
     method public android.view.LayoutInflater getLayoutInflater();
diff --git a/api/system-current.txt b/api/system-current.txt
index 8a633df..7a4b137 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30961,6 +30961,7 @@
   public class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
+    method public void closeSystemDialogs();
     method public void finish();
     method public android.content.Context getContext();
     method public android.view.LayoutInflater getLayoutInflater();
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 7eb936a..a7e0e08 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1001,6 +1001,21 @@
     }
 
     /**
+     * Request that all system dialogs (and status bar shade etc) be closed, allowing
+     * access to the session's UI.  This will <em>not</em> cause the lock screen to be
+     * dismissed.
+     */
+    public void closeSystemDialogs() {
+        if (mToken == null) {
+            throw new IllegalStateException("Can't call before onCreate()");
+        }
+        try {
+            mSystemService.closeSystemDialogs(mToken);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Convenience for inflating views.
      */
     public LayoutInflater getLayoutInflater() {
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index a2bd700..8cd9bab 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -35,6 +35,7 @@
     boolean hideSessionFromSession(IBinder token);
     int startVoiceActivity(IBinder token, in Intent intent, String resolvedType);
     void setKeepAwake(IBinder token, boolean keepAwake);
+    void closeSystemDialogs(IBinder token);
     void finish(IBinder token);
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 959fd37..c7fbc76 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18,9 +18,7 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index cde87bd..61ae1c0 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -545,6 +545,24 @@
         }
 
         @Override
+        public void closeSystemDialogs(IBinder token) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "closeSystemDialogs without running voice interaction service");
+                    return;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    mImpl.closeSystemDialogsLocked(callingPid, callingUid, token);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+        }
+
+        @Override
         public void finish(IBinder token) {
             synchronized (this) {
                 if (mImpl == null) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index af0ddbe..e5faf4d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -48,6 +48,8 @@
 class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
     final static String TAG = "VoiceInteractionServiceManager";
 
+    final static String CLOSE_REASON_VOICE_INTERACTION = "voiceinteraction";
+
     final boolean mValid;
 
     final Context mContext;
@@ -68,11 +70,14 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
-                synchronized (mLock) {
-                    if (mActiveSession != null && mActiveSession.mSession != null) {
-                        try {
-                            mActiveSession.mSession.closeSystemDialogs();
-                        } catch (RemoteException e) {
+                String reason = intent.getStringExtra("reason");
+                if (!CLOSE_REASON_VOICE_INTERACTION.equals(reason)) {
+                    synchronized (mLock) {
+                        if (mActiveSession != null && mActiveSession.mSession != null) {
+                            try {
+                                mActiveSession.mSession.closeSystemDialogs();
+                            } catch (RemoteException e) {
+                            }
                         }
                     }
                 }
@@ -196,6 +201,18 @@
         }
     }
 
+    public void closeSystemDialogsLocked(int callingPid, int callingUid, IBinder token) {
+        try {
+            if (mActiveSession == null || token != mActiveSession.mToken) {
+                Slog.w(TAG, "closeSystemDialogs does not match active session");
+                return;
+            }
+            mAm.closeSystemDialogs(CLOSE_REASON_VOICE_INTERACTION);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Unexpected remote error", e);
+        }
+    }
+
     public void finishLocked(IBinder token) {
         if (mActiveSession == null || token != mActiveSession.mToken) {
             Slog.w(TAG, "finish does not match active session");