Merge changes from topic "am-629d721311684d0894cb70223e57c879"

* changes:
  [automerger skipped] Merge "[DO NOT MERGE] Bouncer - Intercept touch events when not visible" into tm-qpr-dev am: 030b7809d2 am: b2bec98532 -s ours
  [automerger skipped] [DO NOT MERGE] Bouncer - Intercept touch events when not visible am: 96cdb8a262 am: 1734b48777 -s ours
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index f843318..fc5cb4b 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -229,6 +229,35 @@
         }
     }
 
+    /**
+     * Enables visual detection service.
+     *
+     * @param listener to receive visual attention gained/lost events.
+     */
+    public void enableVisualQueryDetection(
+            IVisualQueryDetectionAttentionListener listener) {
+        try {
+            if (mVoiceInteractionManagerService != null) {
+                mVoiceInteractionManagerService.enableVisualQueryDetection(listener);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to register visual query detection attention listener", e);
+        }
+    }
+
+    /**
+     * Disables visual query detection.
+     */
+    public void disableVisualQueryDetection() {
+        try {
+            if (mVoiceInteractionManagerService != null) {
+                mVoiceInteractionManagerService.disableVisualQueryDetection();
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to register visual query detection attention listener", e);
+        }
+    }
+
     @UnsupportedAppUsage
     public ComponentName getAssistComponentForUser(int userId) {
         final String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
diff --git a/core/java/com/android/internal/app/IVisualQueryDetectionAttentionListener.aidl b/core/java/com/android/internal/app/IVisualQueryDetectionAttentionListener.aidl
new file mode 100644
index 0000000..3e48da7
--- /dev/null
+++ b/core/java/com/android/internal/app/IVisualQueryDetectionAttentionListener.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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;
+
+/**
+ * Allows sysui to notify users the assistant is ready to take a query without notifying the
+ * assistant app.
+ */
+oneway interface IVisualQueryDetectionAttentionListener {
+   /**
+    * Called when attention signal is sent.
+    */
+   void onAttentionGained();
+
+   /**
+    * Called when a attention signal is lost.
+    */
+   void onAttentionLost();
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 88d6425..619b420 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -39,6 +39,7 @@
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractionSoundTriggerSession;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.IVisualQueryDetectionAttentionListener;
 
 interface IVoiceInteractionManagerService {
     void showSession(in Bundle sessionArgs, int flags, String attributionTag);
@@ -300,6 +301,12 @@
      */
     void shutdownHotwordDetectionService();
 
+    @EnforcePermission("ACCESS_VOICE_INTERACTION_SERVICE")
+    void enableVisualQueryDetection(in IVisualQueryDetectionAttentionListener Listener);
+
+    @EnforcePermission("ACCESS_VOICE_INTERACTION_SERVICE")
+    void disableVisualQueryDetection();
+
     void startPerceiving(in IVisualQueryDetectionVoiceInteractionCallback callback);
 
     void stopPerceiving();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 445446e..03796de 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -66,6 +66,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
+import com.android.internal.app.IVisualQueryDetectionAttentionListener;
 import com.android.internal.infra.ServiceConnector;
 import com.android.server.LocalServices;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -328,6 +329,15 @@
         session.startListeningFromMicLocked(audioFormat, callback);
     }
 
+    public void setVisualQueryDetectionAttentionListenerLocked(
+            @Nullable IVisualQueryDetectionAttentionListener listener) {
+        final VisualQueryDetectorSession session = getVisualQueryDetectorSessionLocked();
+        if (session == null) {
+            return;
+        }
+        session.setVisualQueryDetectionAttentionListenerLocked(listener);
+    }
+
     /**
      * This method is only used by VisualQueryDetector.
      */
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
index 621c3de..33150d8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VisualQueryDetectorSession.java
@@ -33,6 +33,7 @@
 import android.util.Slog;
 
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
+import com.android.internal.app.IVisualQueryDetectionAttentionListener;
 
 import java.io.PrintWriter;
 import java.util.Objects;
@@ -49,6 +50,7 @@
 final class VisualQueryDetectorSession extends DetectorSession {
 
     private static final String TAG = "VisualQueryDetectorSession";
+    private IVisualQueryDetectionAttentionListener mAttentionListener;
     private boolean mEgressingData;
     private boolean mQueryStreaming;
 
@@ -64,6 +66,7 @@
                 logging);
         mEgressingData = false;
         mQueryStreaming = false;
+        mAttentionListener = null;
     }
 
     @Override
@@ -74,6 +77,11 @@
         //TODO(b/261783819): Starts detection in VisualQueryDetectionService.
     }
 
+    void setVisualQueryDetectionAttentionListenerLocked(
+            @Nullable IVisualQueryDetectionAttentionListener listener) {
+        mAttentionListener = listener;
+    }
+
     @SuppressWarnings("GuardedBy")
     void startPerceivingLocked(IVisualQueryDetectionVoiceInteractionCallback callback) {
         if (DEBUG) {
@@ -86,15 +94,31 @@
             @Override
             public void onAttentionGained() {
                 Slog.v(TAG, "BinderCallback#onAttentionGained");
-                //TODO check to see if there is an active SysUI listener registered
                 mEgressingData = true;
+                if (mAttentionListener == null) {
+                    return;
+                }
+                try {
+                    mAttentionListener.onAttentionGained();
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error delivering attention gained event.", e);
+                    return;
+                }
             }
 
             @Override
             public void onAttentionLost() {
                 Slog.v(TAG, "BinderCallback#onAttentionLost");
-                //TODO check to see if there is an active SysUI listener registered
                 mEgressingData = false;
+                if (mAttentionListener == null) {
+                    return;
+                }
+                try {
+                    mAttentionListener.onAttentionLost();
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error delivering attention lost event.", e);
+                    return;
+                }
             }
 
             @Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 38bf9c2..0abed0b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -87,6 +87,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
+import com.android.internal.app.IVisualQueryDetectionAttentionListener;
 import com.android.internal.app.IVoiceActionCheckCallback;
 import com.android.internal.app.IVoiceInteractionManagerService;
 import com.android.internal.app.IVoiceInteractionSessionListener;
@@ -1338,6 +1339,39 @@
             }
         }
 
+        @android.annotation.EnforcePermission(
+                android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
+        @Override
+        public void enableVisualQueryDetection(
+                IVisualQueryDetectionAttentionListener listener) {
+            super.enableVisualQueryDetection_enforcePermission();
+            synchronized (this) {
+
+                if (mImpl == null) {
+                    Slog.w(TAG,
+                            "enableVisualQueryDetection without running voice interaction service");
+                    return;
+                }
+                this.mImpl.setVisualQueryDetectionAttentionListenerLocked(listener);
+            }
+        }
+
+        @android.annotation.EnforcePermission(
+                android.Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE)
+        @Override
+        public void disableVisualQueryDetection() {
+            super.disableVisualQueryDetection_enforcePermission();
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG,
+                            "disableVisualQueryDetection without running voice interaction"
+                                    + " service");
+                    return;
+                }
+                this.mImpl.setVisualQueryDetectionAttentionListenerLocked(null);
+            }
+        }
+
         @Override
         public void startPerceiving(
                 IVisualQueryDetectionVoiceInteractionCallback callback)
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 127195c..3dbd269 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -72,7 +72,9 @@
 import android.util.Slog;
 import android.view.IWindowManager;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
+import com.android.internal.app.IVisualQueryDetectionAttentionListener;
 import com.android.internal.app.IVoiceActionCheckCallback;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
@@ -247,6 +249,7 @@
                 Context.RECEIVER_EXPORTED);
     }
 
+    @GuardedBy("this")
     public void grantImplicitAccessLocked(int grantRecipientUid, @Nullable Intent intent) {
         final int grantRecipientAppId = UserHandle.getAppId(grantRecipientUid);
         final int grantRecipientUserId = UserHandle.getUserId(grantRecipientUid);
@@ -256,6 +259,7 @@
                 /* direct= */ true);
     }
 
+    @GuardedBy("this")
     public boolean showSessionLocked(@Nullable Bundle args, int flags,
             @Nullable String attributionTag,
             @Nullable IVoiceInteractionSessionShowCallback showCallback,
@@ -328,6 +332,7 @@
         }
     }
 
+    @GuardedBy("this")
     public boolean hideSessionLocked() {
         if (mActiveSession != null) {
             return mActiveSession.hideLocked();
@@ -335,6 +340,7 @@
         return false;
     }
 
+    @GuardedBy("this")
     public boolean deliverNewSessionLocked(IBinder token,
             IVoiceInteractionSession session, IVoiceInteractor interactor) {
         if (mActiveSession == null || token != mActiveSession.mToken) {
@@ -345,6 +351,7 @@
         return true;
     }
 
+    @GuardedBy("this")
     public int startVoiceActivityLocked(@Nullable String callingFeatureId, int callingPid,
             int callingUid, IBinder token, Intent intent, String resolvedType) {
         try {
@@ -367,6 +374,7 @@
         }
     }
 
+    @GuardedBy("this")
     public int startAssistantActivityLocked(@Nullable String callingFeatureId, int callingPid,
             int callingUid, IBinder token, Intent intent, String resolvedType) {
         try {
@@ -389,6 +397,7 @@
         }
     }
 
+    @GuardedBy("this")
     public void requestDirectActionsLocked(@NonNull IBinder token, int taskId,
             @NonNull IBinder assistToken,  @Nullable RemoteCallback cancellationCallback,
             @NonNull RemoteCallback callback) {
@@ -444,6 +453,7 @@
         }
     }
 
+    @GuardedBy("this")
     void performDirectActionLocked(@NonNull IBinder token, @NonNull String actionId,
             @Nullable Bundle arguments, int taskId, IBinder assistToken,
             @Nullable RemoteCallback cancellationCallback,
@@ -470,6 +480,7 @@
         }
     }
 
+    @GuardedBy("this")
     public void setKeepAwakeLocked(IBinder token, boolean keepAwake) {
         try {
             if (mActiveSession == null || token != mActiveSession.mToken) {
@@ -482,6 +493,7 @@
         }
     }
 
+    @GuardedBy("this")
     public void closeSystemDialogsLocked(IBinder token) {
         try {
             if (mActiveSession == null || token != mActiveSession.mToken) {
@@ -494,6 +506,7 @@
         }
     }
 
+    @GuardedBy("this")
     public void finishLocked(IBinder token, boolean finishTask) {
         if (mActiveSession == null || (!finishTask && token != mActiveSession.mToken)) {
             Slog.w(TAG, "finish does not match active session");
@@ -503,6 +516,7 @@
         mActiveSession = null;
     }
 
+    @GuardedBy("this")
     public void setDisabledShowContextLocked(int callingUid, int flags) {
         int activeUid = mInfo.getServiceInfo().applicationInfo.uid;
         if (callingUid != activeUid) {
@@ -512,6 +526,7 @@
         mDisabledShowContext = flags;
     }
 
+    @GuardedBy("this")
     public int getDisabledShowContextLocked(int callingUid) {
         int activeUid = mInfo.getServiceInfo().applicationInfo.uid;
         if (callingUid != activeUid) {
@@ -521,6 +536,7 @@
         return mDisabledShowContext;
     }
 
+    @GuardedBy("this")
     public int getUserDisabledShowContextLocked(int callingUid) {
         int activeUid = mInfo.getServiceInfo().applicationInfo.uid;
         if (callingUid != activeUid) {
@@ -534,6 +550,7 @@
         return mInfo.getSupportsLocalInteraction();
     }
 
+    @GuardedBy("this")
     public void startListeningVisibleActivityChangedLocked(@NonNull IBinder token) {
         if (DEBUG) {
             Slog.d(TAG, "startListeningVisibleActivityChangedLocked: token=" + token);
@@ -546,6 +563,7 @@
         mActiveSession.startListeningVisibleActivityChangedLocked();
     }
 
+    @GuardedBy("this")
     public void stopListeningVisibleActivityChangedLocked(@NonNull IBinder token) {
         if (DEBUG) {
             Slog.d(TAG, "stopListeningVisibleActivityChangedLocked: token=" + token);
@@ -558,6 +576,7 @@
         mActiveSession.stopListeningVisibleActivityChangedLocked();
     }
 
+    @GuardedBy("this")
     public void notifyActivityDestroyedLocked(@NonNull IBinder activityToken) {
         if (DEBUG) {
             Slog.d(TAG, "notifyActivityDestroyedLocked activityToken=" + activityToken);
@@ -572,6 +591,7 @@
         mActiveSession.notifyActivityDestroyedLocked(activityToken);
     }
 
+    @GuardedBy("this")
     public void notifyActivityEventChangedLocked(@NonNull IBinder activityToken, int type) {
         if (DEBUG) {
             Slog.d(TAG, "notifyActivityEventChangedLocked type=" + type);
@@ -586,6 +606,7 @@
         mActiveSession.notifyActivityEventChangedLocked(activityToken, type);
     }
 
+    @GuardedBy("this")
     public void updateStateLocked(
             @Nullable PersistableBundle options,
             @Nullable SharedMemory sharedMemory,
@@ -606,6 +627,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void verifyDetectorForHotwordDetectionLocked(
             @Nullable SharedMemory sharedMemory,
             IHotwordRecognitionStatusCallback callback,
@@ -663,6 +685,7 @@
                 voiceInteractionServiceUid);
     }
 
+    @GuardedBy("this")
     private void verifyDetectorForVisualQueryDetectionLocked(@Nullable SharedMemory sharedMemory) {
         Slog.v(TAG, "verifyDetectorForVisualQueryDetectionLocked");
 
@@ -701,6 +724,7 @@
         }
     }
 
+    @GuardedBy("this")
     public void initAndVerifyDetectorLocked(
             @NonNull Identity voiceInteractorIdentity,
             @Nullable PersistableBundle options,
@@ -730,6 +754,7 @@
                 detectorType);
     }
 
+    @GuardedBy("this")
     public void destroyDetectorLocked(IBinder token) {
         Slog.v(TAG, "destroyDetectorLocked");
 
@@ -748,6 +773,7 @@
         }
     }
 
+    @GuardedBy("this")
     public void shutdownHotwordDetectionServiceLocked() {
         if (DEBUG) {
             Slog.d(TAG, "shutdownHotwordDetectionServiceLocked");
@@ -760,6 +786,16 @@
         mHotwordDetectionConnection = null;
     }
 
+    @GuardedBy("this")
+    public void setVisualQueryDetectionAttentionListenerLocked(
+            @Nullable IVisualQueryDetectionAttentionListener listener) {
+        if (mHotwordDetectionConnection == null) {
+            return;
+        }
+        mHotwordDetectionConnection.setVisualQueryDetectionAttentionListenerLocked(listener);
+    }
+
+    @GuardedBy("this")
     public void startPerceivingLocked(IVisualQueryDetectionVoiceInteractionCallback callback) {
         if (DEBUG) {
             Slog.d(TAG, "startPerceivingLocked");
@@ -773,6 +809,7 @@
         mHotwordDetectionConnection.startPerceivingLocked(callback);
     }
 
+    @GuardedBy("this")
     public void stopPerceivingLocked() {
         if (DEBUG) {
             Slog.d(TAG, "stopPerceivingLocked");
@@ -786,6 +823,7 @@
         mHotwordDetectionConnection.stopPerceivingLocked();
     }
 
+    @GuardedBy("this")
     public void startListeningFromMicLocked(
             AudioFormat audioFormat,
             IMicrophoneHotwordDetectionVoiceInteractionCallback callback) {
@@ -801,6 +839,7 @@
         mHotwordDetectionConnection.startListeningFromMicLocked(audioFormat, callback);
     }
 
+    @GuardedBy("this")
     public void startListeningFromExternalSourceLocked(
             ParcelFileDescriptor audioStream,
             AudioFormat audioFormat,
@@ -825,6 +864,7 @@
                 options, token, callback);
     }
 
+    @GuardedBy("this")
     public void stopListeningFromMicLocked() {
         if (DEBUG) {
             Slog.d(TAG, "stopListeningFromMicLocked");
@@ -838,6 +878,7 @@
         mHotwordDetectionConnection.stopListeningFromMicLocked();
     }
 
+    @GuardedBy("this")
     public void triggerHardwareRecognitionEventForTestLocked(
             SoundTrigger.KeyphraseRecognitionEvent event,
             IHotwordRecognitionStatusCallback callback) {
@@ -852,6 +893,7 @@
         mHotwordDetectionConnection.triggerHardwareRecognitionEventForTestLocked(event, callback);
     }
 
+    @GuardedBy("this")
     public IRecognitionStatusCallback createSoundTriggerCallbackLocked(
             IHotwordRecognitionStatusCallback callback) {
         if (DEBUG) {
@@ -876,6 +918,7 @@
         return null;
     }
 
+    @GuardedBy("this")
     boolean isIsolatedProcessLocked(@NonNull ServiceInfo serviceInfo) {
         return (serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
                 && (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0;
@@ -889,6 +932,7 @@
         mHotwordDetectionConnection.forceRestart();
     }
 
+    @GuardedBy("this")
     void setDebugHotwordLoggingLocked(boolean logging) {
         if (mHotwordDetectionConnection == null) {
             Slog.w(TAG, "Failed to set temporary debug logging: no hotword detection active");
@@ -897,6 +941,7 @@
         mHotwordDetectionConnection.setDebugHotwordLoggingLocked(logging);
     }
 
+    @GuardedBy("this")
     void resetHotwordDetectionConnectionLocked() {
         if (DEBUG) {
             Slog.d(TAG, "resetHotwordDetectionConnectionLocked");
@@ -911,6 +956,7 @@
         mHotwordDetectionConnection = null;
     }
 
+    @GuardedBy("this")
     public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!mValid) {
             pw.print("  NOT VALID: ");
@@ -947,6 +993,7 @@
         }
     }
 
+    @GuardedBy("this")
     void startLocked() {
         Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
         intent.setComponent(mComponent);
@@ -971,6 +1018,7 @@
         }
     }
 
+    @GuardedBy("this")
     void shutdownLocked() {
         // If there is an active session, cancel it to allow it to clean up its window and other
         // state.
@@ -998,6 +1046,7 @@
         }
     }
 
+    @GuardedBy("this")
     void notifySoundModelsChangedLocked() {
         if (mService == null) {
             Slog.w(TAG, "Not bound to voice interaction service " + mComponent);