diff options
| author | Peter Li <lpeter@google.com> | 2021-03-29 11:43:29 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2021-03-29 11:43:29 +0000 |
| commit | 378b540fa1721fb63000715ceb225df407bbdb7c (patch) | |
| tree | 267e6a06ec621de9ec83d904116a0fd09ec7dae3 /core/java/android | |
| parent | d4a142719ea698fb8b4908dc992f2d6ee8798a21 (diff) | |
| parent | 6f2a2638105c2af9d8f8a215b0cd9e2ed257e2b5 (diff) | |
Merge "Add callback to report HotwordDetectionService status" into sc-dev
Diffstat (limited to 'core/java/android')
5 files changed, 128 insertions, 14 deletions
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 73e0da16e049..8ca0e7ccff37 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -48,6 +48,7 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SharedMemory; +import android.service.voice.HotwordDetectionService.InitializationStatus; import android.util.Slog; import com.android.internal.app.IHotwordRecognitionStatusCallback; @@ -260,6 +261,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { private static final int MSG_DETECTION_PAUSE = 4; private static final int MSG_DETECTION_RESUME = 5; private static final int MSG_HOTWORD_REJECTED = 6; + private static final int MSG_HOTWORD_STATUS_REPORTED = 7; private final String mText; private final Locale mLocale; @@ -523,6 +525,15 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { */ public void onRejected(@Nullable HotwordRejectedResult result) { } + + /** + * Called when the {@link HotwordDetectionService} is created by the system and given a + * short amount of time to report it's initialization state. + * + * @param status Info about initialization state of {@link HotwordDetectionService}. + */ + public void onHotwordDetectionServiceInitialized(@InitializationStatus int status) { + } } /** @@ -559,7 +570,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { mTargetSdkVersion = targetSdkVersion; mSupportHotwordDetectionService = supportHotwordDetectionService; if (mSupportHotwordDetectionService) { - updateState(options, sharedMemory); + updateStateLocked(options, sharedMemory, mInternalCallback); } try { Identity identity = new Identity(); @@ -583,20 +594,34 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { * such data to the trusted process. * * @throws IllegalStateException if this AlwaysOnHotwordDetector wasn't specified to use a - * {@link HotwordDetectionService} when it was created. + * {@link HotwordDetectionService} when it was created. In addition, if this + * AlwaysOnHotwordDetector is in an invalid or error state. */ public final void updateState(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory) { if (DBG) { Slog.d(TAG, "updateState()"); } - if (!mSupportHotwordDetectionService) { - throw new IllegalStateException( - "updateState called, but it doesn't support hotword detection service"); + synchronized (mLock) { + if (!mSupportHotwordDetectionService) { + throw new IllegalStateException( + "updateState called, but it doesn't support hotword detection service"); + } + if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) { + throw new IllegalStateException( + "updateState called on an invalid detector or error state"); + } + updateStateLocked(options, sharedMemory, null /* callback */); } + } + private void updateStateLocked(@Nullable PersistableBundle options, + @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) { + if (DBG) { + Slog.d(TAG, "updateStateLocked()"); + } try { - mModelManagementService.updateState(options, sharedMemory); + mModelManagementService.updateState(options, sharedMemory, callback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1147,6 +1172,18 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { Slog.i(TAG, "onRecognitionResumed"); mHandler.sendEmptyMessage(MSG_DETECTION_RESUME); } + + @Override + public void onStatusReported(int status) { + if (DBG) { + Slog.d(TAG, "onStatusReported(" + status + ")"); + } else { + Slog.i(TAG, "onStatusReported"); + } + Message message = Message.obtain(mHandler, MSG_HOTWORD_STATUS_REPORTED); + message.arg1 = status; + message.sendToTarget(); + } } class MyHandler extends Handler { @@ -1178,6 +1215,9 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { case MSG_HOTWORD_REJECTED: mExternalCallback.onRejected((HotwordRejectedResult) msg.obj); break; + case MSG_HOTWORD_STATUS_REPORTED: + mExternalCallback.onHotwordDetectionServiceInitialized(msg.arg1); + break; default: super.handleMessage(msg); } diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java index fb731a094f90..7c14c2e19eb1 100644 --- a/core/java/android/service/voice/HotwordDetectionService.java +++ b/core/java/android/service/voice/HotwordDetectionService.java @@ -37,10 +37,13 @@ import android.os.RemoteException; import android.os.SharedMemory; import android.util.Log; +import com.android.internal.app.IHotwordRecognitionStatusCallback; + import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Locale; +import java.util.function.IntConsumer; /** * Implemented by an application that wants to offer detection for hotword. The system will @@ -54,6 +57,39 @@ public abstract class HotwordDetectionService extends Service { // TODO (b/177502877): Set the Debug flag to false before shipping. private static final boolean DBG = true; + private static final long UPDATE_TIMEOUT_MILLIS = 5000; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "INITIALIZATION_STATUS_" }, value = { + INITIALIZATION_STATUS_SUCCESS, + INITIALIZATION_STATUS_CUSTOM_ERROR_1, + INITIALIZATION_STATUS_CUSTOM_ERROR_2, + INITIALIZATION_STATUS_UNKNOWN, + }) + public @interface InitializationStatus {} + + /** + * Indicates that the updated status is successful. + */ + public static final int INITIALIZATION_STATUS_SUCCESS = 0; + + /** + * Indicates that the updated status is failure for some application specific reasons. + */ + public static final int INITIALIZATION_STATUS_CUSTOM_ERROR_1 = 1; + + /** + * Indicates that the updated status is failure for some application specific reasons. + */ + public static final int INITIALIZATION_STATUS_CUSTOM_ERROR_2 = 2; + + /** + * Indicates that the callback wasn’t invoked within the timeout. + * This is used by system. + */ + public static final int INITIALIZATION_STATUS_UNKNOWN = 100; + /** * Source for the given audio stream. * @@ -104,15 +140,16 @@ public abstract class HotwordDetectionService extends Service { } @Override - public void updateState(PersistableBundle options, SharedMemory sharedMemory) - throws RemoteException { + public void updateState(PersistableBundle options, SharedMemory sharedMemory, + IHotwordRecognitionStatusCallback callback) throws RemoteException { if (DBG) { Log.d(TAG, "#updateState"); } - mHandler.sendMessage(obtainMessage(HotwordDetectionService::onUpdateState, + mHandler.sendMessage(obtainMessage(HotwordDetectionService::onUpdateStateInternal, HotwordDetectionService.this, options, - sharedMemory)); + sharedMemory, + callback)); } @Override @@ -207,12 +244,20 @@ public abstract class HotwordDetectionService extends Service { * @param sharedMemory The unrestricted data blob to provide to the * {@link HotwordDetectionService}. Use this to provide the hotword models data or other * such data to the trusted process. + * @param callbackTimeoutMillis Timeout in milliseconds for the operation to invoke the + * statusCallback. + * @param statusCallback Use this to return the updated result. This is non-null only when the + * {@link HotwordDetectionService} is being initialized; and it is null if the state is updated + * after that. * * @hide */ @SystemApi - public void onUpdateState(@Nullable PersistableBundle options, - @Nullable SharedMemory sharedMemory) { + public void onUpdateState( + @Nullable PersistableBundle options, + @Nullable SharedMemory sharedMemory, + @DurationMillisLong long callbackTimeoutMillis, + @Nullable @InitializationStatus IntConsumer statusCallback) { // TODO: Handle the unimplemented case by throwing? } @@ -268,6 +313,23 @@ public abstract class HotwordDetectionService extends Service { throw new UnsupportedOperationException(); } + private void onUpdateStateInternal(@Nullable PersistableBundle options, + @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) { + // TODO (b/183684347): Implement timeout case. + IntConsumer intConsumer = null; + if (callback != null) { + intConsumer = + value -> { + try { + callback.onStatusReported(value); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + }; + } + onUpdateState(options, sharedMemory, UPDATE_TIMEOUT_MILLIS, intConsumer); + } + /** * Callback for returning the detection result. * diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java index 26491245914f..f4e5ddaa31a6 100644 --- a/core/java/android/service/voice/HotwordDetector.java +++ b/core/java/android/service/voice/HotwordDetector.java @@ -27,6 +27,7 @@ import android.annotation.SystemApi; import android.media.AudioFormat; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; +import android.service.voice.HotwordDetectionService.InitializationStatus; /** * Basic functionality for hotword detectors. @@ -144,5 +145,13 @@ public interface HotwordDetector { * {@link HotwordDetectionService}. */ void onRejected(@Nullable HotwordRejectedResult result); + + /** + * Called when the {@link HotwordDetectionService} is created by the system and given a + * short amount of time to report it's initialization state. + * + * @param status Info about initialization state of {@link HotwordDetectionService}. + */ + void onHotwordDetectionServiceInitialized(@InitializationStatus int status); } } diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl index cb140f9346fa..cac8333a5855 100644 --- a/core/java/android/service/voice/IHotwordDetectionService.aidl +++ b/core/java/android/service/voice/IHotwordDetectionService.aidl @@ -22,6 +22,8 @@ import android.os.PersistableBundle; import android.os.SharedMemory; import android.service.voice.IDspHotwordDetectionCallback; +import com.android.internal.app.IHotwordRecognitionStatusCallback; + /** * Provide the interface to communicate with hotword detection service. * @@ -41,5 +43,6 @@ oneway interface IHotwordDetectionService { in PersistableBundle options, in IDspHotwordDetectionCallback callback); - void updateState(in PersistableBundle options, in SharedMemory sharedMemory); + void updateState(in PersistableBundle options, in SharedMemory sharedMemory, + in IHotwordRecognitionStatusCallback callback); } diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java index f49a9d45ae06..376596b9b0d0 100644 --- a/core/java/android/service/voice/SoftwareHotwordDetector.java +++ b/core/java/android/service/voice/SoftwareHotwordDetector.java @@ -67,7 +67,7 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector { mHandler = new Handler(Looper.getMainLooper()); try { - mManagerService.updateState(options, sharedMemory); + mManagerService.updateState(options, sharedMemory, null /* callback */); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } |
