summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorIvan Chiang <chiangi@google.com>2022-07-18 15:28:46 +0800
committerIvan Chiang <chiangi@google.com>2022-08-12 14:35:33 +0800
commit525690ce16c1c7a48b7880897a4349e2dda0ca09 (patch)
tree090b4314c4f6d7b35a540e95c384269c8510576c /core/java/android
parentea3ccf17fe6f68601f17d5e8ce05b081063f71c7 (diff)
[RESTRICT AUTOMERGE] Check permission for VoiceInteraction
The service must have the CAPTURE_AUDIO_HOTWORD permission to access AlwaysOnHotwordDetector. If it doesn't have the permission, return STATE_HARDWARE_UNAVAILABLE state. If it is not granted the RECORD_AUDIO permisison, it also can't start to recognize the audio. Test: manual Test: atest CtsVoiceInteractionTestCases Test: atest CtsAssistTestCases Bug: 229793943 Change-Id: I7d0f8d2f6af4bc4210060f0a44469db2afc7a1bb
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java57
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java2
2 files changed, 55 insertions, 4 deletions
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 6f941121771e..b956d1918f7e 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -16,12 +16,14 @@
package android.service.voice;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
import android.hardware.soundtrigger.KeyphraseMetadata;
@@ -232,8 +234,10 @@ public class AlwaysOnHotwordDetector {
private final Callback mExternalCallback;
private final Object mLock = new Object();
private final Handler mHandler;
+ private final Context mContext;
private int mAvailability = STATE_NOT_READY;
+ private boolean mIsGrantedHotwordPermission;
/**
* A ModelParamRange is a representation of supported parameter range for a
@@ -408,23 +412,37 @@ public class AlwaysOnHotwordDetector {
public abstract void onRecognitionResumed();
}
+ private static boolean hasHotwordPermission(Context context) {
+ return context.checkSelfPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private static boolean hasRecordAudioPermission(Context context) {
+ return context.checkSelfPermission(Manifest.permission.RECORD_AUDIO)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
/**
+ * @param context The context to check permission
* @param text The keyphrase text to get the detector for.
* @param locale The java locale for the detector.
* @param callback A non-null Callback for receiving the recognition events.
+ * @param keyphraseEnrollmentInfo The Enrollment info of key phrase
* @param modelManagementService A service that allows management of sound models.
* @hide
*/
- public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback,
+ public AlwaysOnHotwordDetector(Context context, String text, Locale locale, Callback callback,
KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
IVoiceInteractionManagerService modelManagementService) {
mText = text;
+ mContext = context;
mLocale = locale;
mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo;
mExternalCallback = callback;
mHandler = new MyHandler();
mInternalCallback = new SoundTriggerListener(mHandler);
mModelManagementService = modelManagementService;
+ mIsGrantedHotwordPermission = hasHotwordPermission(mContext);
new RefreshAvailabiltyTask().execute();
}
@@ -477,6 +495,11 @@ public class AlwaysOnHotwordDetector {
@AudioCapabilities
public int getSupportedAudioCapabilities() {
if (DBG) Slog.d(TAG, "getSupportedAudioCapabilities()");
+
+ if (!mIsGrantedHotwordPermission) {
+ return 0;
+ }
+
synchronized (mLock) {
return getSupportedAudioCapabilitiesLocked();
}
@@ -515,6 +538,12 @@ public class AlwaysOnHotwordDetector {
*/
public boolean startRecognition(@RecognitionFlags int recognitionFlags) {
if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")");
+
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ throw new IllegalStateException("Must have the RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD "
+ + "permissions to access the detector.");
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("startRecognition called on an invalid detector");
@@ -545,6 +574,12 @@ public class AlwaysOnHotwordDetector {
*/
public boolean stopRecognition() {
if (DBG) Slog.d(TAG, "stopRecognition()");
+
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ throw new IllegalStateException("Must have the RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD "
+ + "permissions to access the detector.");
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("stopRecognition called on an invalid detector");
@@ -582,6 +617,10 @@ public class AlwaysOnHotwordDetector {
Slog.d(TAG, "setParameter(" + modelParam + ", " + value + ")");
}
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ return SoundTrigger.STATUS_INVALID_OPERATION;
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("setParameter called on an invalid detector");
@@ -609,6 +648,10 @@ public class AlwaysOnHotwordDetector {
Slog.d(TAG, "getParameter(" + modelParam + ")");
}
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ return MODEL_PARAM_THRESHOLD_FACTOR;
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("getParameter called on an invalid detector");
@@ -634,6 +677,10 @@ public class AlwaysOnHotwordDetector {
Slog.d(TAG, "queryParameter(" + modelParam + ")");
}
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ return null;
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("queryParameter called on an invalid detector");
@@ -742,8 +789,8 @@ public class AlwaysOnHotwordDetector {
*/
void onSoundModelsChanged() {
synchronized (mLock) {
- if (mAvailability == STATE_INVALID
- || mAvailability == STATE_HARDWARE_UNAVAILABLE) {
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_HARDWARE_UNAVAILABLE
+ || !hasRecordAudioPermission(mContext)) {
Slog.w(TAG, "Received onSoundModelsChanged for an unsupported keyphrase/config");
return;
}
@@ -962,6 +1009,10 @@ public class AlwaysOnHotwordDetector {
* @return The initial availability without checking the enrollment status.
*/
private int internalGetInitialAvailability() {
+ if (!mIsGrantedHotwordPermission) {
+ return STATE_HARDWARE_UNAVAILABLE;
+ }
+
synchronized (mLock) {
// This detector has already been invalidated.
if (mAvailability == STATE_INVALID) {
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 45d3465fdae8..a56d40790dbf 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -318,7 +318,7 @@ public class VoiceInteractionService extends Service {
synchronized (mLock) {
// Allow only one concurrent recognition via the APIs.
safelyShutdownHotwordDetector();
- mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
+ mHotwordDetector = new AlwaysOnHotwordDetector(this, keyphrase, locale, callback,
mKeyphraseEnrollmentInfo, mSystemService);
}
return mHotwordDetector;