Loading core/api/system-current.txt +7 −1 Original line number Diff line number Diff line Loading @@ -10372,6 +10372,7 @@ package android.service.voice { public abstract static class AlwaysOnHotwordDetector.Callback implements android.service.voice.HotwordDetector.Callback { ctor public AlwaysOnHotwordDetector.Callback(); method public abstract void onAvailabilityChanged(int); method public void onHotwordDetectionServiceInitialized(int); method public void onRejected(@Nullable android.service.voice.HotwordRejectedResult); } Loading Loading @@ -10419,7 +10420,11 @@ package android.service.voice { method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.Callback); method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @NonNull android.service.voice.HotwordDetectionService.Callback); method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @NonNull android.service.voice.HotwordDetectionService.Callback); method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory); method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer); field public static final int INITIALIZATION_STATUS_CUSTOM_ERROR_1 = 1; // 0x1 field public static final int INITIALIZATION_STATUS_CUSTOM_ERROR_2 = 2; // 0x2 field public static final int INITIALIZATION_STATUS_SUCCESS = 0; // 0x0 field public static final int INITIALIZATION_STATUS_UNKNOWN = 100; // 0x64 field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService"; } Loading @@ -10441,6 +10446,7 @@ package android.service.voice { public static interface HotwordDetector.Callback { method public void onDetected(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload); method public void onError(); method public void onHotwordDetectionServiceInitialized(int); method public void onRecognitionPaused(); method public void onRecognitionResumed(); method public void onRejected(@Nullable android.service.voice.HotwordRejectedResult); core/java/android/service/voice/AlwaysOnHotwordDetector.java +46 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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) { } } /** Loading Loading @@ -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(); Loading @@ -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()"); } 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(); } Loading Loading @@ -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 { Loading Loading @@ -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); } Loading core/java/android/service/voice/HotwordDetectionService.java +68 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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. * Loading Loading @@ -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 Loading Loading @@ -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? } Loading Loading @@ -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. * Loading core/java/android/service/voice/HotwordDetector.java +9 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); } } core/java/android/service/voice/IHotwordDetectionService.aidl +4 −1 Original line number Diff line number Diff line Loading @@ -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. * Loading @@ -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); } Loading
core/api/system-current.txt +7 −1 Original line number Diff line number Diff line Loading @@ -10372,6 +10372,7 @@ package android.service.voice { public abstract static class AlwaysOnHotwordDetector.Callback implements android.service.voice.HotwordDetector.Callback { ctor public AlwaysOnHotwordDetector.Callback(); method public abstract void onAvailabilityChanged(int); method public void onHotwordDetectionServiceInitialized(int); method public void onRejected(@Nullable android.service.voice.HotwordRejectedResult); } Loading Loading @@ -10419,7 +10420,11 @@ package android.service.voice { method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.Callback); method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @NonNull android.service.voice.HotwordDetectionService.Callback); method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @NonNull android.service.voice.HotwordDetectionService.Callback); method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory); method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer); field public static final int INITIALIZATION_STATUS_CUSTOM_ERROR_1 = 1; // 0x1 field public static final int INITIALIZATION_STATUS_CUSTOM_ERROR_2 = 2; // 0x2 field public static final int INITIALIZATION_STATUS_SUCCESS = 0; // 0x0 field public static final int INITIALIZATION_STATUS_UNKNOWN = 100; // 0x64 field public static final String SERVICE_INTERFACE = "android.service.voice.HotwordDetectionService"; } Loading @@ -10441,6 +10446,7 @@ package android.service.voice { public static interface HotwordDetector.Callback { method public void onDetected(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload); method public void onError(); method public void onHotwordDetectionServiceInitialized(int); method public void onRecognitionPaused(); method public void onRecognitionResumed(); method public void onRejected(@Nullable android.service.voice.HotwordRejectedResult);
core/java/android/service/voice/AlwaysOnHotwordDetector.java +46 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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) { } } /** Loading Loading @@ -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(); Loading @@ -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()"); } 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(); } Loading Loading @@ -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 { Loading Loading @@ -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); } Loading
core/java/android/service/voice/HotwordDetectionService.java +68 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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. * Loading Loading @@ -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 Loading Loading @@ -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? } Loading Loading @@ -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. * Loading
core/java/android/service/voice/HotwordDetector.java +9 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); } }
core/java/android/service/voice/IHotwordDetectionService.aidl +4 −1 Original line number Diff line number Diff line Loading @@ -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. * Loading @@ -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); }