diff options
| author | 2023-03-15 18:13:44 +0000 | |
|---|---|---|
| committer | 2023-03-15 18:13:44 +0000 | |
| commit | 05bd77c0b4864e4643af7f23ff9ce820b1303008 (patch) | |
| tree | 3540a8fe27e0a226460afc23587a73d62dc64e42 | |
| parent | cc10548a5f2fa2bd0c5a14c89ed3b11f90108d5a (diff) | |
| parent | 2ed6c794052596d9c439e3f20cc1622d84d74fac (diff) | |
Merge "Revert "update HotwordDetector exception throws"" into udc-dev
7 files changed, 115 insertions, 341 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index fb7ce5bb9f86..0352c07f1525 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -12993,20 +12993,20 @@ package android.service.trust { package android.service.voice { public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector { - method @Nullable public android.content.Intent createEnrollIntent() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @Nullable public android.content.Intent createReEnrollIntent() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @Nullable public android.content.Intent createUnEnrollIntent() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int getParameter(int) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; + method @Nullable public android.content.Intent createEnrollIntent(); + method @Nullable public android.content.Intent createReEnrollIntent(); + method @Nullable public android.content.Intent createUnEnrollIntent(); + method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int getParameter(int); method public int getSupportedAudioCapabilities(); - method public int getSupportedRecognitionModes() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @Nullable @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public android.service.voice.AlwaysOnHotwordDetector.ModelParamRange queryParameter(int) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int setParameter(int, int) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(int, @NonNull byte[]) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(int) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean stopRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method public final void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; + method public int getSupportedRecognitionModes(); + method @Nullable @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public android.service.voice.AlwaysOnHotwordDetector.ModelParamRange queryParameter(int); + method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public int setParameter(int, int); + method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(int, @NonNull byte[]); + method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(int); + method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(); + method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle); + method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean stopRecognition(); + method public final void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory); field public static final int AUDIO_CAPABILITY_ECHO_CANCELLATION = 1; // 0x1 field public static final int AUDIO_CAPABILITY_NOISE_SUPPRESSION = 2; // 0x2 field public static final int MODEL_PARAM_THRESHOLD_FACTOR = 0; // 0x0 @@ -13185,10 +13185,10 @@ package android.service.voice { public interface HotwordDetector { method public default void destroy(); - method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method public boolean stopRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method public void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; + method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public boolean startRecognition(); + method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle); + method public boolean stopRecognition(); + method public void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory); } public static interface HotwordDetector.Callback { @@ -13202,9 +13202,6 @@ package android.service.voice { method public void onRejected(@NonNull android.service.voice.HotwordRejectedResult); } - public static class HotwordDetector.IllegalDetectorStateException extends android.util.AndroidException { - } - public final class HotwordRejectedResult implements android.os.Parcelable { method public int describeContents(); method public int getConfidenceLevel(); @@ -13272,9 +13269,9 @@ package android.service.voice { public class VisualQueryDetector { method public void destroy(); - method @RequiresPermission(allOf={android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO}) public boolean startRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method @RequiresPermission(allOf={android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO}) public boolean stopRecognition() throws android.service.voice.HotwordDetector.IllegalDetectorStateException; - method public void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory) throws android.service.voice.HotwordDetector.IllegalDetectorStateException; + method @RequiresPermission(allOf={android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO}) public boolean startRecognition(); + method @RequiresPermission(allOf={android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO}) public boolean stopRecognition(); + method public void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory); } public static interface VisualQueryDetector.Callback { diff --git a/core/java/android/service/voice/AbstractDetector.java b/core/java/android/service/voice/AbstractDetector.java index 644a2bfa70bd..0f3e8d1f4bde 100644 --- a/core/java/android/service/voice/AbstractDetector.java +++ b/core/java/android/service/voice/AbstractDetector.java @@ -20,7 +20,6 @@ import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; -import android.app.compat.CompatChanges; import android.media.AudioFormat; import android.media.permission.Identity; import android.os.Binder; @@ -100,7 +99,7 @@ abstract class AbstractDetector implements HotwordDetector { public boolean startRecognition( @NonNull ParcelFileDescriptor audioStream, @NonNull AudioFormat audioFormat, - @Nullable PersistableBundle options) throws IllegalDetectorStateException { + @Nullable PersistableBundle options) { if (DEBUG) { Slog.i(TAG, "#recognizeHotword"); } @@ -132,18 +131,13 @@ abstract class AbstractDetector implements HotwordDetector { * @param sharedMemory The unrestricted data blob to provide to the * {@link VisualQueryDetectionService} and {@link HotwordDetectionService}. Use this to * provide the hotword models data or other such data to the trusted process. - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of - * Android Tiramisu or above and attempts to start a recognition when the detector is - * not able based on the state. Because the caller receives updates via an asynchronous - * callback and the state of the detector can change without caller's knowledge, a - * checked exception is thrown. * @throws IllegalStateException if this {@link HotwordDetector} wasn't specified to use a * {@link HotwordDetectionService} or {@link VisualQueryDetectionService} when it was * created. */ @Override public void updateState(@Nullable PersistableBundle options, - @Nullable SharedMemory sharedMemory) throws IllegalDetectorStateException { + @Nullable SharedMemory sharedMemory) { if (DEBUG) { Slog.d(TAG, "updateState()"); } @@ -199,13 +193,9 @@ abstract class AbstractDetector implements HotwordDetector { } } - protected void throwIfDetectorIsNoLongerActive() throws IllegalDetectorStateException { + protected void throwIfDetectorIsNoLongerActive() { if (!mIsDetectorActive.get()) { Slog.e(TAG, "attempting to use a destroyed detector which is no longer active"); - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "attempting to use a destroyed detector which is no longer active"); - } throw new IllegalStateException( "attempting to use a destroyed detector which is no longer active"); } diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 2830fb7750e4..ffa15f065a02 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -827,28 +827,19 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { /** * {@inheritDoc} * - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above and this AlwaysOnHotwordDetector wasn't specified to use a - * {@link HotwordDetectionService} when it was created. In addition, the exception can - * be thrown if this AlwaysOnHotwordDetector is in an invalid or error state. - * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if - * this AlwaysOnHotwordDetector wasn't specified to use a - * {@link HotwordDetectionService} when it was created. In addition, the exception can - * be thrown if this AlwaysOnHotwordDetector is in an invalid or error state. + * @throws IllegalStateException if this AlwaysOnHotwordDetector wasn't specified to use a + * {@link HotwordDetectionService} when it was created. In addition, if this + * AlwaysOnHotwordDetector is in an invalid or error state. */ @Override public final void updateState(@Nullable PersistableBundle options, - @Nullable SharedMemory sharedMemory) throws IllegalDetectorStateException { + @Nullable SharedMemory sharedMemory) { synchronized (mLock) { if (!mSupportSandboxedDetectionService) { throw new IllegalStateException( "updateState called, but it doesn't support hotword detection service"); } if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "updateState called on an invalid detector or error state"); - } throw new IllegalStateException( "updateState called on an invalid detector or error state"); } @@ -869,17 +860,16 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { @TestApi public void overrideAvailability(int availability) { synchronized (mLock) { + mAvailability = availability; + mIsAvailabilityOverriddenByTestApi = true; // ENROLLED state requires there to be metadata about the sound model so a fake one // is created. - if (mKeyphraseMetadata == null && availability == STATE_KEYPHRASE_ENROLLED) { + if (mKeyphraseMetadata == null && mAvailability == STATE_KEYPHRASE_ENROLLED) { Set<Locale> fakeSupportedLocales = new HashSet<>(); fakeSupportedLocales.add(mLocale); mKeyphraseMetadata = new KeyphraseMetadata(1, mText, fakeSupportedLocales, AlwaysOnHotwordDetector.RECOGNITION_MODE_VOICE_TRIGGER); } - - mAvailability = availability; - mIsAvailabilityOverriddenByTestApi = true; notifyStateChangedLocked(); } } @@ -935,23 +925,14 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * @see #RECOGNITION_MODE_USER_IDENTIFICATION * @see #RECOGNITION_MODE_VOICE_TRIGGER * - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above. Because the caller receives availability updates via an asynchronous - * callback, it may be due to the availability changing while this call is performed. - * - Throws if the detector is in an invalid or error state. - * This may happen if another detector has been instantiated or the - * {@link VoiceInteractionService} hosting this detector has been shut down. - * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level - * 33 Android if the recognition isn't supported. Callers should only call this method - * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to - * avoid this exception. - * @throws IllegalStateException Thrown when a caller has a target SDK below Android API level - * 33 if the detector is in an invalid or error state. This may happen if another - * detector has been instantiated or the {@link VoiceInteractionService} hosting this - * detector has been shut down. + * @throws UnsupportedOperationException if the keyphrase itself isn't supported. + * Callers should only call this method after a supported state callback on + * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. + * @throws IllegalStateException if the detector is in an invalid or error state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ - public @RecognitionModes - int getSupportedRecognitionModes() throws IllegalDetectorStateException { + public @RecognitionModes int getSupportedRecognitionModes() { if (DBG) Slog.d(TAG, "getSupportedRecognitionModes()"); synchronized (mLock) { return getSupportedRecognitionModesLocked(); @@ -959,22 +940,14 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { } @GuardedBy("mLock") - private int getSupportedRecognitionModesLocked() throws IllegalDetectorStateException { + private int getSupportedRecognitionModesLocked() { if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException("getSupportedRecognitionModes called on an" - + " invalid detector or error state"); - } throw new IllegalStateException( "getSupportedRecognitionModes called on an invalid detector or error state"); } // This method only makes sense if we can actually support a recognition. if (mAvailability != STATE_KEYPHRASE_ENROLLED || mKeyphraseMetadata == null) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException("Getting supported recognition modes for" - + " the keyphrase is not supported"); - } throw new UnsupportedOperationException( "Getting supported recognition modes for the keyphrase is not supported"); } @@ -1029,30 +1002,15 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * startRecognition request. This data is intended to provide additional parameters * when starting the opaque sound model. * @return Indicates whether the call succeeded or not. - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above and attempts to start a recognition when the detector is not able based on - * the availability state. This can be thrown even if the state has been checked before - * calling this method because the caller receives availability updates via an - * asynchronous callback, it may be due to the availability changing while this call is - * performed. - * - Throws if the recognition isn't supported. - * Callers should only call this method after a supported state callback on - * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. - * - Also throws if the detector is in an invalid or error state. - * This may happen if another detector has been instantiated or the - * {@link VoiceInteractionService} hosting this detector has been shut down. - * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level - * 33 Android if the recognition isn't supported. Callers should only call this method - * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to - * avoid this exception. - * @throws IllegalStateException Thrown when a caller has a target SDK below Android API level - * 33 if the detector is in an invalid or error state. This may happen if another - * detector has been instantiated or the {@link VoiceInteractionService} hosting this - * detector has been shut down. + * @throws UnsupportedOperationException if the recognition isn't supported. + * Callers should only call this method after a supported state callback on + * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. + * @throws IllegalStateException if the detector is in an invalid or error state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD}) - public boolean startRecognition(@RecognitionFlags int recognitionFlags, @NonNull byte[] data) - throws IllegalDetectorStateException { + public boolean startRecognition(@RecognitionFlags int recognitionFlags, @NonNull byte[] data) { synchronized (mLock) { return startRecognitionLocked(recognitionFlags, data) == STATUS_OK; @@ -1069,30 +1027,15 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * * @param recognitionFlags The flags to control the recognition properties. * @return Indicates whether the call succeeded or not. - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above and attempts to start a recognition when the detector is not able based on - * the availability state. This can be thrown even if the state has been checked before - * calling this method because the caller receives availability updates via an - * asynchronous callback, it may be due to the availability changing while this call is - * performed. - * - Throws if the recognition isn't supported. - * Callers should only call this method after a supported state callback on - * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. - * - Also throws if the detector is in an invalid or error state. - * This may happen if another detector has been instantiated or the - * {@link VoiceInteractionService} hosting this detector has been shut down. - * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level - * 33 if the recognition isn't supported. Callers should only call this method after a - * supported state callback on {@link Callback#onAvailabilityChanged(int)} to avoid this - * exception. - * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the - * detector is in an invalid or error state. This may happen if another detector has - * been instantiated or the {@link VoiceInteractionService} hosting this detector has - * been shut down. + * @throws UnsupportedOperationException if the recognition isn't supported. + * Callers should only call this method after a supported state callback on + * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. + * @throws IllegalStateException if the detector is in an invalid or error state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD}) - public boolean startRecognition(@RecognitionFlags int recognitionFlags) - throws IllegalDetectorStateException { + public boolean startRecognition(@RecognitionFlags int recognitionFlags) { if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")"); synchronized (mLock) { return startRecognitionLocked(recognitionFlags, null /* data */) == STATUS_OK; @@ -1106,8 +1049,7 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { */ @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD}) @Override - public boolean startRecognition() - throws IllegalDetectorStateException { + public boolean startRecognition() { return startRecognition(0); } @@ -1117,44 +1059,28 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * Settings.Secure.VOICE_INTERACTION_SERVICE. * * @return Indicates whether the call succeeded or not. - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of - * API level 33 or above and attempts to stop a recognition when the detector is - * not able based on the state. This can be thrown even if the state has been checked - * before calling this method because the caller receives availability updates via an - * asynchronous callback, it may be due to the availability changing while this call is - * performed. - * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level - * 33 if the recognition isn't supported. Callers should only call this method after a - * supported state callback on {@link Callback#onAvailabilityChanged(int)} to avoid this - * exception. - * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the - * detector is in an invalid or error state. This may happen if another detector has - * been instantiated or the {@link VoiceInteractionService} hosting this detector has - * been shut down. + * @throws UnsupportedOperationException if the recognition isn't supported. + * Callers should only call this method after a supported state callback on + * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. + * @throws IllegalStateException if the detector is in an invalid or error state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ // TODO: Remove this RequiresPermission since it isn't actually enforced. Also fix the javadoc // about permissions enforcement (when it throws vs when it just returns false) for other // methods in this class. @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD}) @Override - public boolean stopRecognition() throws IllegalDetectorStateException { + public boolean stopRecognition() { if (DBG) Slog.d(TAG, "stopRecognition()"); synchronized (mLock) { if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "stopRecognition called on an invalid detector or error state"); - } throw new IllegalStateException( "stopRecognition called on an invalid detector or error state"); } // Check if we can start/stop a recognition. if (mAvailability != STATE_KEYPHRASE_ENROLLED) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "Recognition for the given keyphrase is not supported"); - } throw new UnsupportedOperationException( "Recognition for the given keyphrase is not supported"); } @@ -1179,28 +1105,18 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or * if API is not supported by HAL - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * if the detector is in an invalid or error state. This may happen if another detector - * has been instantiated or the {@link VoiceInteractionService} hosting this detector - * has been shut down. - * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the - * detector is in an invalid or error state. This may happen if another detector has - * been instantiated or the {@link VoiceInteractionService} hosting this detector has - * been shut down. + * @throws IllegalStateException if the detector is in an invalid or error state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD}) - public int setParameter(@ModelParams int modelParam, int value) - throws IllegalDetectorStateException { + public int setParameter(@ModelParams int modelParam, int value) { if (DBG) { Slog.d(TAG, "setParameter(" + modelParam + ", " + value + ")"); } synchronized (mLock) { if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "setParameter called on an invalid detector or error state"); - } throw new IllegalStateException( "setParameter called on an invalid detector or error state"); } @@ -1221,27 +1137,18 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * * @param modelParam {@link ModelParams} * @return value of parameter - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * if the detector is in an invalid or error state. This may happen if another detector - * has been instantiated or the {@link VoiceInteractionService} hosting this detector - * has been shut down. - * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if - * the detector is in an invalid or error state. This may happen if another detector has - * been instantiated or the {@link VoiceInteractionService} hosting this detector has - * been shut down. + * @throws IllegalStateException if the detector is in an invalid or error state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD}) - public int getParameter(@ModelParams int modelParam) throws IllegalDetectorStateException { + public int getParameter(@ModelParams int modelParam) { if (DBG) { Slog.d(TAG, "getParameter(" + modelParam + ")"); } synchronized (mLock) { if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "getParameter called on an invalid detector or error state"); - } throw new IllegalStateException( "getParameter called on an invalid detector or error state"); } @@ -1259,29 +1166,19 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * * @param modelParam {@link ModelParams} * @return supported range of parameter, null if not supported - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * if the detector is in an invalid or error state. This may happen if another detector - * has been instantiated or the {@link VoiceInteractionService} hosting this detector - * has been shut down. - * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if - * the detector is in an invalid or error state. This may happen if another detector has - * been instantiated or the {@link VoiceInteractionService} hosting this detector has - * been shut down. + * @throws IllegalStateException if the detector is in an invalid or error state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD}) @Nullable - public ModelParamRange queryParameter(@ModelParams int modelParam) - throws IllegalDetectorStateException { + public ModelParamRange queryParameter(@ModelParams int modelParam) { if (DBG) { Slog.d(TAG, "queryParameter(" + modelParam + ")"); } synchronized (mLock) { if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "queryParameter called on an invalid detector or error state"); - } throw new IllegalStateException( "queryParameter called on an invalid detector or error state"); } @@ -1298,25 +1195,15 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * otherwise {@link #createReEnrollIntent()} should be preferred. * * @return An {@link Intent} to start enrollment for the given keyphrase. - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above. - * - Thrown if managing they keyphrase isn't supported. Callers should only call this - * method after a supported state callback on - * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. - * - Thrown if the detector is in an invalid state. This may happen if another detector - * has been instantiated or the {@link VoiceInteractionService} hosting this detector - * has been shut down. - * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level - * 33 if managing they keyphrase isn't supported. Callers should only call this method - * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to - * avoid this exception. - * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the - * detector is in an invalid state. This may happen if another detector has been - * instantiated or the {@link VoiceInteractionService} hosting this detector has been - * shut down. + * @throws UnsupportedOperationException if managing they keyphrase isn't supported. + * Callers should only call this method after a supported state callback on + * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. + * @throws IllegalStateException if the detector is in an invalid state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ @Nullable - public Intent createEnrollIntent() throws IllegalDetectorStateException { + public Intent createEnrollIntent() { if (DBG) Slog.d(TAG, "createEnrollIntent"); synchronized (mLock) { return getManageIntentLocked(KeyphraseEnrollmentInfo.MANAGE_ACTION_ENROLL); @@ -1330,25 +1217,15 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error. * * @return An {@link Intent} to start un-enrollment for the given keyphrase. - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above. - * - Thrown if managing they keyphrase isn't supported. Callers should only call this - * method after a supported state callback on - * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. - * - Thrown if the detector is in an invalid state. This may happen if another detector - * has been instantiated or the {@link VoiceInteractionService} hosting this detector - * has been shut down. - * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level - * 33 if managing they keyphrase isn't supported. Callers should only call this method - * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to - * avoid this exception. - * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the - * detector is in an invalid state. This may happen if another detector has been - * instantiated or the {@link VoiceInteractionService} hosting this detector has been - * shut down. + * @throws UnsupportedOperationException if managing they keyphrase isn't supported. + * Callers should only call this method after a supported state callback on + * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. + * @throws IllegalStateException if the detector is in an invalid state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ @Nullable - public Intent createUnEnrollIntent() throws IllegalDetectorStateException { + public Intent createUnEnrollIntent() { if (DBG) Slog.d(TAG, "createUnEnrollIntent"); synchronized (mLock) { return getManageIntentLocked(KeyphraseEnrollmentInfo.MANAGE_ACTION_UN_ENROLL); @@ -1362,25 +1239,15 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { * i.e. {@link #STATE_KEYPHRASE_ENROLLED}, otherwise invoking this may result in an error. * * @return An {@link Intent} to start re-enrollment for the given keyphrase. - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above. - * - Thrown if managing they keyphrase isn't supported. Callers should only call this - * method after a supported state callback on - * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. - * - Thrown if the detector is in an invalid state. This may happen if another detector - * has been instantiated or the {@link VoiceInteractionService} hosting this detector - * has been shut down. - * @throws UnsupportedOperationException Thrown when a caller has a target SDK below API level - * 33 if managing they keyphrase isn't supported. Callers should only call this method - * after a supported state callback on {@link Callback#onAvailabilityChanged(int)} to - * avoid this exception. - * @throws IllegalStateException Thrown when a caller has a target SDK below API level 33 if the - * detector is in an invalid state. This may happen if another detector has been - * instantiated or the {@link VoiceInteractionService} hosting this detector has been - * shut down. + * @throws UnsupportedOperationException if managing they keyphrase isn't supported. + * Callers should only call this method after a supported state callback on + * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. + * @throws IllegalStateException if the detector is in an invalid or error state. + * This may happen if another detector has been instantiated or the + * {@link VoiceInteractionService} hosting this detector has been shut down. */ @Nullable - public Intent createReEnrollIntent() throws IllegalDetectorStateException { + public Intent createReEnrollIntent() { if (DBG) Slog.d(TAG, "createReEnrollIntent"); synchronized (mLock) { return getManageIntentLocked(KeyphraseEnrollmentInfo.MANAGE_ACTION_RE_ENROLL); @@ -1388,24 +1255,15 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { } @GuardedBy("mLock") - private Intent getManageIntentLocked(@KeyphraseEnrollmentInfo.ManageActions int action) - throws IllegalDetectorStateException { + private Intent getManageIntentLocked(@KeyphraseEnrollmentInfo.ManageActions int action) { if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "getManageIntent called on an invalid detector or error state"); - } throw new IllegalStateException( - "getManageIntent called on an invalid detector or error state"); + "getManageIntent called on an invalid detector or error state"); } // This method only makes sense if we can actually support a recognition. if (mAvailability != STATE_KEYPHRASE_ENROLLED && mAvailability != STATE_KEYPHRASE_UNENROLLED) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "Managing the given keyphrase is not supported"); - } throw new UnsupportedOperationException( "Managing the given keyphrase is not supported"); } @@ -1489,27 +1347,19 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { @GuardedBy("mLock") private int startRecognitionLocked(int recognitionFlags, - @Nullable byte[] data) throws IllegalDetectorStateException { + @Nullable byte[] data) { if (DBG) { Slog.d(TAG, "startRecognition(" + recognitionFlags + ", " + Arrays.toString(data) + ")"); } if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "startRecognition called on an invalid detector or error state"); - } throw new IllegalStateException( "startRecognition called on an invalid detector or error state"); } // Check if we can start/stop a recognition. if (mAvailability != STATE_KEYPHRASE_ENROLLED) { - if (CompatChanges.isChangeEnabled(HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION)) { - throw new IllegalDetectorStateException( - "Recognition for the given keyphrase is not supported"); - } throw new UnsupportedOperationException( "Recognition for the given keyphrase is not supported"); } diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java index 93fcec14cf1c..0c8fd48a39d2 100644 --- a/core/java/android/service/voice/HotwordDetector.java +++ b/core/java/android/service/voice/HotwordDetector.java @@ -23,14 +23,10 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; import android.media.AudioFormat; -import android.os.Build; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.SharedMemory; -import android.util.AndroidException; import java.io.PrintWriter; @@ -44,23 +40,6 @@ import java.io.PrintWriter; public interface HotwordDetector { /** - * Prior to API level 33, API calls of {@link android.service.voice.HotwordDetector} could - * return both {@link java.lang.IllegalStateException} or - * {@link java.lang.UnsupportedOperationException} depending on the detector's underlying state. - * This lead to confusing behavior as the underlying state of the detector can be modified - * without the knowledge of the caller via system service layer updates. - * - * This change ID, when enabled, changes the API calls to only throw checked exception - * {@link android.service.voice.HotwordDetector.IllegalDetectorStateException} when checking - * against state information modified by both the caller and the system services. - * - * @hide - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) - long HOTWORD_DETECTOR_THROW_CHECKED_EXCEPTION = 226355112L; - - /** * Indicates that it is a non-trusted hotword detector. * * @hide @@ -109,26 +88,16 @@ public interface HotwordDetector { * Calling this again while recognition is active does nothing. * * @return {@code true} if the request to start recognition succeeded - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above and attempts to start a recognition when the detector is not able based on - * the state. This can be thrown even if the state has been checked before calling this - * method because the caller receives updates via an asynchronous callback, and the - * state of the detector can change concurrently to the caller calling this method. */ @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD}) - boolean startRecognition() throws IllegalDetectorStateException; + boolean startRecognition(); /** * Stops sandboxed detection recognition. * * @return {@code true} if the request to stop recognition succeeded - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above and attempts to stop a recognition when the detector is not able based on - * the state. This can be thrown even if the state has been checked before calling this - * method because the caller receives updates via an asynchronous callback, and the - * state of the detector can change concurrently to the caller calling this method. */ - boolean stopRecognition() throws IllegalDetectorStateException; + boolean stopRecognition(); /** * Starts hotword recognition on audio coming from an external connected microphone. @@ -142,16 +111,11 @@ public interface HotwordDetector { * PersistableBundle does not allow any remotable objects or other contents that can be * used to communicate with other processes. * @return {@code true} if the request to start recognition succeeded - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above and attempts to start a recognition when the detector is not able based on - * the state. This can be thrown even if the state has been checked before calling this - * method because the caller receives updates via an asynchronous callback, and the - * state of the detector can change concurrently to the caller calling this method. */ boolean startRecognition( @NonNull ParcelFileDescriptor audioStream, @NonNull AudioFormat audioFormat, - @Nullable PersistableBundle options) throws IllegalDetectorStateException; + @Nullable PersistableBundle options); /** * Set configuration and pass read-only data to sandboxed detection service. @@ -161,17 +125,10 @@ public interface HotwordDetector { * communicate with other processes. * @param sharedMemory The unrestricted data blob to provide to sandboxed detection services. * Use this to provide model data or other such data to the trusted process. - * @throws IllegalDetectorStateException Thrown when a caller has a target SDK of API level 33 - * or above and the detector is not able to perform the operation based on the - * underlying state. This can be thrown even if the state has been checked before - * calling this method because the caller receives updates via an asynchronous callback, - * and the state of the detector can change concurrently to the caller calling this - * method. * @throws IllegalStateException if this HotwordDetector wasn't specified to use a * sandboxed detection service when it was created. */ - void updateState(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory) - throws IllegalDetectorStateException; + void updateState(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory); /** * Invalidates this detector so that any future calls to this result @@ -298,14 +255,4 @@ public interface HotwordDetector { */ void onHotwordDetectionServiceRestarted(); } - - /** - * {@link HotwordDetector} specific exception thrown when the underlying state of the detector - * is invalid for the given action. - */ - class IllegalDetectorStateException extends AndroidException { - IllegalDetectorStateException(String message) { - super(message); - } - } } diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java index 767fe378a30c..77900d7bcb5a 100644 --- a/core/java/android/service/voice/SoftwareHotwordDetector.java +++ b/core/java/android/service/voice/SoftwareHotwordDetector.java @@ -86,7 +86,7 @@ class SoftwareHotwordDetector extends AbstractDetector { @RequiresPermission(RECORD_AUDIO) @Override - public boolean startRecognition() throws IllegalDetectorStateException { + public boolean startRecognition() { if (DEBUG) { Slog.i(TAG, "#startRecognition"); } @@ -109,7 +109,7 @@ class SoftwareHotwordDetector extends AbstractDetector { /** TODO: stopRecognition */ @RequiresPermission(RECORD_AUDIO) @Override - public boolean stopRecognition() throws IllegalDetectorStateException { + public boolean stopRecognition() { if (DEBUG) { Slog.i(TAG, "#stopRecognition"); } diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java index 7dc0687b549d..d7bf07498715 100644 --- a/core/java/android/service/voice/VisualQueryDetector.java +++ b/core/java/android/service/voice/VisualQueryDetector.java @@ -84,8 +84,7 @@ public class VisualQueryDetector { * @see HotwordDetector#updateState(PersistableBundle, SharedMemory) */ public void updateState(@Nullable PersistableBundle options, - @Nullable SharedMemory sharedMemory) throws - HotwordDetector.IllegalDetectorStateException { + @Nullable SharedMemory sharedMemory) { mInitializationDelegate.updateState(options, sharedMemory); } @@ -104,7 +103,7 @@ public class VisualQueryDetector { * @see HotwordDetector#startRecognition() */ @RequiresPermission(allOf = {CAMERA, RECORD_AUDIO}) - public boolean startRecognition() throws HotwordDetector.IllegalDetectorStateException { + public boolean startRecognition() { if (DEBUG) { Slog.i(TAG, "#startRecognition"); } @@ -128,7 +127,7 @@ public class VisualQueryDetector { * @see HotwordDetector#stopRecognition() */ @RequiresPermission(allOf = {CAMERA, RECORD_AUDIO}) - public boolean stopRecognition() throws HotwordDetector.IllegalDetectorStateException { + public boolean stopRecognition() { if (DEBUG) { Slog.i(TAG, "#stopRecognition"); } @@ -236,13 +235,13 @@ public class VisualQueryDetector { } @Override - public boolean stopRecognition() throws IllegalDetectorStateException { + public boolean stopRecognition() { throwIfDetectorIsNoLongerActive(); return true; } @Override - public boolean startRecognition() throws IllegalDetectorStateException { + public boolean startRecognition() { throwIfDetectorIsNoLongerActive(); return true; } @@ -251,7 +250,7 @@ public class VisualQueryDetector { public final boolean startRecognition( @NonNull ParcelFileDescriptor audioStream, @NonNull AudioFormat audioFormat, - @Nullable PersistableBundle options) throws IllegalDetectorStateException { + @Nullable PersistableBundle options) { //No-op, not supported by VisualQueryDetector as it should be trusted. return false; } diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java index f183a9b1d46c..b7f5b15f72ac 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java @@ -20,7 +20,6 @@ import android.content.Intent; import android.service.voice.AlwaysOnHotwordDetector; import android.service.voice.AlwaysOnHotwordDetector.Callback; import android.service.voice.AlwaysOnHotwordDetector.EventPayload; -import android.service.voice.HotwordDetector; import android.service.voice.VoiceInteractionService; import android.util.Log; @@ -84,24 +83,16 @@ public class MainInteractionService extends VoiceInteractionService { break; case AlwaysOnHotwordDetector.STATE_KEYPHRASE_UNENROLLED: Log.i(TAG, "STATE_KEYPHRASE_UNENROLLED"); - try { - Intent enroll = mHotwordDetector.createEnrollIntent(); - Log.i(TAG, "Need to enroll with " + enroll); - } catch (HotwordDetector.IllegalDetectorStateException e) { - Log.e(TAG, "createEnrollIntent failed", e); - } + Intent enroll = mHotwordDetector.createEnrollIntent(); + Log.i(TAG, "Need to enroll with " + enroll); break; case AlwaysOnHotwordDetector.STATE_KEYPHRASE_ENROLLED: Log.i(TAG, "STATE_KEYPHRASE_ENROLLED - starting recognition"); - try { - if (mHotwordDetector.startRecognition( - AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE)) { - Log.i(TAG, "startRecognition succeeded"); - } else { - Log.i(TAG, "startRecognition failed"); - } - } catch (HotwordDetector.IllegalDetectorStateException e) { - Log.e(TAG, "startRecognition failed", e); + if (mHotwordDetector.startRecognition( + AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE)) { + Log.i(TAG, "startRecognition succeeded"); + } else { + Log.i(TAG, "startRecognition failed"); } break; } |