summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt8
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java52
-rw-r--r--core/java/android/service/voice/HotwordDetectionService.java74
-rw-r--r--core/java/android/service/voice/HotwordDetector.java9
-rw-r--r--core/java/android/service/voice/IHotwordDetectionService.aidl5
-rw-r--r--core/java/android/service/voice/SoftwareHotwordDetector.java2
-rw-r--r--core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl8
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl7
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java6
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java4
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java4
11 files changed, 156 insertions, 23 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 49b8a901bcbb..062c56069215 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -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);
}
@@ -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";
}
@@ -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);
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();
}
diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
index 23314e7be622..9bec505c801d 100644
--- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
+++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
@@ -66,4 +66,12 @@ oneway interface IHotwordRecognitionStatusCallback {
* Called when the recognition is resumed after it was temporarily paused.
*/
void onRecognitionResumed();
+
+ /**
+ * Called when the {@link HotwordDetectionService} reported the result for requesting update
+ * state action.
+ *
+ * @param status The status about the result of requesting update state action.
+ */
+ void onStatusReported(int status);
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index bb6233bc772d..fffeb024caae 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -26,6 +26,7 @@ import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.SharedMemory;
+import com.android.internal.app.IHotwordRecognitionStatusCallback;
import com.android.internal.app.IVoiceActionCheckCallback;
import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
@@ -238,8 +239,12 @@ interface IVoiceInteractionManagerService {
* @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 callback Use this to report {@link HotwordDetectionService} status.
*/
- void updateState(in PersistableBundle options, in SharedMemory sharedMemory);
+ void updateState(
+ in PersistableBundle options,
+ in SharedMemory sharedMemory,
+ in IHotwordRecognitionStatusCallback callback);
/**
* Requests to shutdown hotword detection service.
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index bbfb0d6a392b..5d541e9cab5d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -93,7 +93,7 @@ final class HotwordDetectionConnection {
HotwordDetectionConnection(Object lock, Context context, ComponentName serviceName,
int userId, boolean bindInstantServiceAllowed, @Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory) {
+ @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) {
mLock = lock;
mContext = context;
mDetectionComponentName = serviceName;
@@ -111,7 +111,7 @@ final class HotwordDetectionConnection {
mBound = connected;
if (connected) {
try {
- service.updateState(options, sharedMemory);
+ service.updateState(options, sharedMemory, callback);
} catch (RemoteException e) {
// TODO: (b/181842909) Report an error to voice interactor
Slog.w(TAG, "Failed to updateState for HotwordDetectionService", e);
@@ -146,7 +146,7 @@ final class HotwordDetectionConnection {
void updateStateLocked(PersistableBundle options, SharedMemory sharedMemory) {
mRemoteHotwordDetectionService.run(
- service -> service.updateState(options, sharedMemory));
+ service -> service.updateState(options, sharedMemory, null /* callback */));
}
void startListeningFromMic(
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index d66f21fba1ab..ccaeaf991467 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1026,7 +1026,7 @@ public class VoiceInteractionManagerService extends SystemService {
@Override
public void updateState(@Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory) {
+ @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) {
enforceCallingPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION);
synchronized (this) {
enforceIsCurrentVoiceInteractionService();
@@ -1037,7 +1037,7 @@ public class VoiceInteractionManagerService extends SystemService {
}
final long caller = Binder.clearCallingIdentity();
try {
- mImpl.updateStateLocked(options, sharedMemory);
+ mImpl.updateStateLocked(options, sharedMemory, callback);
} finally {
Binder.restoreCallingIdentity(caller);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index efa7f78e22aa..6922ccc03d0b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -405,7 +405,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
}
public void updateStateLocked(@Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory) {
+ @Nullable SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) {
if (DEBUG) {
Slog.d(TAG, "updateStateLocked");
}
@@ -427,7 +427,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
if (mHotwordDetectionConnection == null) {
mHotwordDetectionConnection = new HotwordDetectionConnection(mServiceStub, mContext,
mHotwordDetectionComponentName, mUser, /* bindInstantServiceAllowed= */ false,
- options, sharedMemory);
+ options, sharedMemory, callback);
} else {
mHotwordDetectionConnection.updateStateLocked(options, sharedMemory);
}