diff --git a/samples/VoiceInteractionService/AndroidManifest.xml b/samples/VoiceInteractionService/AndroidManifest.xml
index 56c959081..bc8ac2779 100755
--- a/samples/VoiceInteractionService/AndroidManifest.xml
+++ b/samples/VoiceInteractionService/AndroidManifest.xml
@@ -3,7 +3,8 @@
-
+
@@ -12,7 +13,8 @@
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:exported="true">
@@ -26,6 +28,12 @@
android:isolatedProcess="true"
android:exported="true">
+
+
diff --git a/samples/VoiceInteractionService/README.md b/samples/VoiceInteractionService/README.md
index 6ac92d17a..92a12cfed 100644
--- a/samples/VoiceInteractionService/README.md
+++ b/samples/VoiceInteractionService/README.md
@@ -1,4 +1,6 @@
setup:
+
+(If a log error "VisualQueryDetector is only available if multiple detectors are allowed" , set target_sdk_version: "10000" in Android.bp for now.)
1. Set the KEYPHRASE constant in SampleVoiceInteractionService.java to something the device's
default assistant supports.
2. m -j SampleVoiceInteractor
diff --git a/samples/VoiceInteractionService/res/xml/voice_interaction.xml b/samples/VoiceInteractionService/res/xml/voice_interaction.xml
index 8445652a2..2c4a5d9a0 100644
--- a/samples/VoiceInteractionService/res/xml/voice_interaction.xml
+++ b/samples/VoiceInteractionService/res/xml/voice_interaction.xml
@@ -17,7 +17,8 @@
+ android:supportsLocalInteraction="true" />
\ No newline at end of file
diff --git a/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/MainActivity.java b/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/MainActivity.java
index deda4f42f..7272531ef 100644
--- a/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/MainActivity.java
+++ b/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/MainActivity.java
@@ -54,7 +54,7 @@ public class MainActivity extends Activity {
return;
}
try {
- mService.mDetector.startRecognition();
+ mService.mHotwordDetector.startRecognition();
} catch (HotwordDetector.IllegalDetectorStateException e) {
e.printStackTrace();
}
@@ -66,7 +66,7 @@ public class MainActivity extends Activity {
Log.e(TAG, "No service");
return;
}
- mService.mCallback.onDetected(mService.mLastPayload, true);
+ mService.mHotwordDetectorCallback.onDetected(mService.mLastPayload, true);
});
}
diff --git a/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/SampleVisualQueryDetectionService.java b/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/SampleVisualQueryDetectionService.java
new file mode 100644
index 000000000..bcd0b4639
--- /dev/null
+++ b/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/SampleVisualQueryDetectionService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.example.android.voiceinteractor;
+
+import android.os.PersistableBundle;
+import android.os.SharedMemory;
+import android.service.voice.VisualQueryDetectionService;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.util.function.IntConsumer;
+
+public class SampleVisualQueryDetectionService extends VisualQueryDetectionService {
+ static final String TAG = "SVisualQueryDetectionSrvc";
+
+ @Override
+ public void onUpdateState(@Nullable PersistableBundle options,
+ @Nullable SharedMemory sharedMemory, long callbackTimeoutMillis,
+ @Nullable IntConsumer statusCallback) {
+ Log.i(TAG, "onUpdateState");
+ if (statusCallback != null) {
+ statusCallback.accept(0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/SampleVoiceInteractionService.java b/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/SampleVoiceInteractionService.java
index 73f91676d..7e19cb86e 100644
--- a/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/SampleVoiceInteractionService.java
+++ b/samples/VoiceInteractionService/src/com/example/android/voiceinteractor/SampleVoiceInteractionService.java
@@ -35,6 +35,7 @@ import android.service.voice.AlwaysOnHotwordDetector.EventPayload;
import android.service.voice.HotwordDetector;
import android.service.voice.HotwordDetector.IllegalDetectorStateException;
import android.service.voice.HotwordRejectedResult;
+import android.service.voice.VisualQueryDetector;
import android.service.voice.VoiceInteractionService;
import android.util.Log;
@@ -42,6 +43,7 @@ import androidx.annotation.NonNull;
import java.time.Duration;
import java.util.Locale;
+import java.util.concurrent.Executors;
public class SampleVoiceInteractionService extends VoiceInteractionService {
public static final String DSP_MODEL_KEYPHRASE = "X Google";
@@ -56,8 +58,10 @@ public class SampleVoiceInteractionService extends VoiceInteractionService {
private final IBinder binder = new LocalBinder();
- HotwordDetector mDetector;
- Callback mCallback;
+ HotwordDetector mHotwordDetector;
+ VisualQueryDetector mVisualQueryDetector;
+ Callback mHotwordDetectorCallback;
+ VisualQueryDetector.Callback mVisualQueryDetectorCallback;
Bundle mData = new Bundle();
AudioFormat mAudioFormat;
EventPayload mLastPayload;
@@ -94,9 +98,12 @@ public class SampleVoiceInteractionService extends VoiceInteractionService {
public void onReady() {
super.onReady();
Log.i(TAG, "onReady");
- mCallback = new Callback();
- mDetector = createAlwaysOnHotwordDetector(DSP_MODEL_KEYPHRASE, DSP_MODEL_LOCALE, null, null,
- mCallback);
+ mHotwordDetectorCallback = new Callback();
+ mVisualQueryDetectorCallback = new VisualQueryDetectorCallback();
+ mHotwordDetector = createAlwaysOnHotwordDetector(DSP_MODEL_KEYPHRASE, DSP_MODEL_LOCALE, null, null,
+ mHotwordDetectorCallback);
+ mVisualQueryDetector = createVisualQueryDetector(null, null,
+ Executors.newSingleThreadExecutor(), mVisualQueryDetectorCallback);
}
@Override
@@ -112,6 +119,38 @@ public class SampleVoiceInteractionService extends VoiceInteractionService {
}
}
+ static class VisualQueryDetectorCallback implements VisualQueryDetector.Callback {
+ @Override
+ public void onQueryDetected(@NonNull String partialQuery) {
+ Log.i(TAG, "VQD partial query detected: "+ partialQuery);
+ }
+
+ @Override
+ public void onQueryRejected() {
+ Log.i(TAG, "VQD query rejected");
+ }
+
+ @Override
+ public void onQueryFinished() {
+ Log.i(TAG, "VQD query finished");
+ }
+
+ @Override
+ public void onVisualQueryDetectionServiceInitialized(int status) {
+ Log.i(TAG, "VQD init: "+ status);
+ }
+
+ @Override
+ public void onVisualQueryDetectionServiceRestarted() {
+ Log.i(TAG, "VQD restarted");
+ }
+
+ @Override
+ public void onError() {
+ Log.i(TAG, "VQD error");
+ }
+ };
+
class Callback extends AlwaysOnHotwordDetector.Callback {
private boolean mAvailable = false;
@@ -131,7 +170,7 @@ public class SampleVoiceInteractionService extends VoiceInteractionService {
if (status == STATE_KEYPHRASE_UNENROLLED) {
Intent enrollIntent = null;
try {
- enrollIntent = ((AlwaysOnHotwordDetector) mDetector).createEnrollIntent();
+ enrollIntent = ((AlwaysOnHotwordDetector) mHotwordDetector).createEnrollIntent();
} catch (IllegalDetectorStateException e) {
e.printStackTrace();
}
@@ -152,7 +191,7 @@ public class SampleVoiceInteractionService extends VoiceInteractionService {
@Override
public void onRejected(@NonNull HotwordRejectedResult result) {
try {
- mDetector.startRecognition();
+ mHotwordDetector.startRecognition();
} catch (IllegalDetectorStateException e) {
e.printStackTrace();
}
@@ -198,7 +237,7 @@ public class SampleVoiceInteractionService extends VoiceInteractionService {
record.getState());
Log.e(TAG, "Failed to init first AudioRecord.");
try {
- mDetector.startRecognition();
+ mHotwordDetector.startRecognition();
} catch (IllegalDetectorStateException e) {
e.printStackTrace();
}
@@ -231,7 +270,7 @@ public class SampleVoiceInteractionService extends VoiceInteractionService {
mLastPayload = eventPayload;
try {
- mDetector.startRecognition();
+ mHotwordDetector.startRecognition();
} catch (IllegalDetectorStateException e) {
e.printStackTrace();
}
@@ -241,7 +280,7 @@ public class SampleVoiceInteractionService extends VoiceInteractionService {
public void onError() {
Log.i(TAG, "onError");
try {
- mDetector.startRecognition();
+ mHotwordDetector.startRecognition();
} catch (IllegalDetectorStateException e) {
e.printStackTrace();
}
@@ -263,7 +302,7 @@ public class SampleVoiceInteractionService extends VoiceInteractionService {
+ ". mAvailable=" + mAvailable);
if (mAvailable) {
try {
- mDetector.startRecognition();
+ mHotwordDetector.startRecognition();
} catch (IllegalDetectorStateException e) {
e.printStackTrace();
}