summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java13
-rw-r--r--core/java/com/android/internal/app/ISoundTriggerSession.aidl2
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionSoundTriggerSession.aidl3
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerDetector.java16
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java156
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java6
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java15
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java10
9 files changed, 151 insertions, 72 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 972995bf74e9..7833eda405e6 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5061,6 +5061,7 @@ package android.media.soundtrigger {
field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION = 4; // 0x4
field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 8; // 0x8
+ field public static final int RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER = 16; // 0x10
}
public abstract static class SoundTriggerDetector.Callback {
@@ -10204,6 +10205,7 @@ package android.service.voice {
field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION = 4; // 0x4
field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 8; // 0x8
+ field public static final int RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER = 16; // 0x10
field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
field public static final int RECOGNITION_MODE_VOICE_TRIGGER = 1; // 0x1
field public static final int STATE_ERROR = 3; // 0x3
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index e934fa483ebe..117b769d6405 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -125,6 +125,7 @@ public class AlwaysOnHotwordDetector {
RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS,
RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION,
RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION,
+ RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER,
})
public @interface RecognitionFlags {}
@@ -171,6 +172,14 @@ public class AlwaysOnHotwordDetector {
*/
public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 0x8;
+ /**
+ * Recognition flag for {@link #startRecognition(int)} that indicates whether the recognition
+ * should continue after battery saver mode is enabled.
+ * When this flag is specified, the caller will be checked for
+ * {@link android.Manifest.permission#SOUND_TRIGGER_RUN_IN_BATTERY_SAVER} permission granted.
+ */
+ public static final int RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER = 0x10;
+
//---- Recognition mode flags. Return codes for getSupportedRecognitionModes() ----//
// Must be kept in sync with the related attribute defined as searchKeyphraseRecognitionFlags.
@@ -860,6 +869,7 @@ public class AlwaysOnHotwordDetector {
(recognitionFlags&RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO) != 0;
boolean allowMultipleTriggers =
(recognitionFlags&RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS) != 0;
+ boolean runInBatterySaver = (recognitionFlags&RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER) != 0;
int audioCapabilities = 0;
if ((recognitionFlags & RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION) != 0) {
@@ -874,7 +884,8 @@ public class AlwaysOnHotwordDetector {
code = mSoundTriggerSession.startRecognition(
mKeyphraseMetadata.getId(), mLocale.toLanguageTag(), mInternalCallback,
new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
- recognitionExtra, null /* additional data */, audioCapabilities));
+ recognitionExtra, null /* additional data */, audioCapabilities),
+ runInBatterySaver);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/com/android/internal/app/ISoundTriggerSession.aidl b/core/java/com/android/internal/app/ISoundTriggerSession.aidl
index ec7d282522c8..a1ba558a5e7f 100644
--- a/core/java/com/android/internal/app/ISoundTriggerSession.aidl
+++ b/core/java/com/android/internal/app/ISoundTriggerSession.aidl
@@ -37,7 +37,7 @@ interface ISoundTriggerSession {
void deleteSoundModel(in ParcelUuid soundModelId);
int startRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback,
- in SoundTrigger.RecognitionConfig config);
+ in SoundTrigger.RecognitionConfig config, boolean runInBatterySaver);
int stopRecognition(in ParcelUuid soundModelId, in IRecognitionStatusCallback callback);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionSoundTriggerSession.aidl b/core/java/com/android/internal/app/IVoiceInteractionSoundTriggerSession.aidl
index 33aab4132150..614926072601 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionSoundTriggerSession.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionSoundTriggerSession.aidl
@@ -41,7 +41,8 @@ interface IVoiceInteractionSoundTriggerSession {
*/
int startRecognition(int keyphraseId, in String bcp47Locale,
in IRecognitionStatusCallback callback,
- in SoundTrigger.RecognitionConfig recognitionConfig);
+ in SoundTrigger.RecognitionConfig recognitionConfig,
+ boolean runInBatterySaver);
/**
* Stops a recognition for the given keyphrase.
* Caller must be the active voice interaction service via
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index 0a1eefae59d6..d9c8a240fa1a 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -79,7 +79,8 @@ public final class SoundTriggerDetector {
RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO,
RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS,
RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION,
- RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION,
+ RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION,
+ RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER,
})
public @interface RecognitionFlags {}
@@ -133,6 +134,14 @@ public final class SoundTriggerDetector {
public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 0x8;
/**
+ * Recognition flag for {@link #startRecognition(int)} that indicates whether the recognition
+ * should continue after battery saver mode is enabled.
+ * When this flag is specified, the caller will be checked for
+ * {@link android.Manifest.permission#SOUND_TRIGGER_RUN_IN_BATTERY_SAVER} permission granted.
+ */
+ public static final int RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER = 0x10;
+
+ /**
* Additional payload for {@link Callback#onDetected}.
*/
public static class EventPayload {
@@ -296,6 +305,8 @@ public final class SoundTriggerDetector {
boolean allowMultipleTriggers =
(recognitionFlags & RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS) != 0;
+ boolean runInBatterySaver = (recognitionFlags & RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER) != 0;
+
int audioCapabilities = 0;
if ((recognitionFlags & RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION) != 0) {
audioCapabilities |= SoundTrigger.ModuleProperties.AUDIO_CAPABILITY_ECHO_CANCELLATION;
@@ -308,7 +319,8 @@ public final class SoundTriggerDetector {
try {
status = mSoundTriggerSession.startRecognition(new ParcelUuid(mSoundModelId),
mRecognitionCallback, new RecognitionConfig(captureTriggerAudio,
- allowMultipleTriggers, null, null, audioCapabilities));
+ allowMultipleTriggers, null, null, audioCapabilities),
+ runInBatterySaver);
} catch (RemoteException e) {
return false;
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 283fae563ea3..16d83d133fbe 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -44,7 +44,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
-import android.os.PowerManager.ServiceType;
+import android.os.PowerManager.SoundTriggerPowerSaveMode;
import android.os.RemoteException;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
@@ -107,7 +107,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private HashMap<Integer, UUID> mKeyphraseUuidMap;
private boolean mCallActive = false;
- private boolean mIsPowerSaveMode = false;
+ private @SoundTriggerPowerSaveMode int mSoundTriggerPowerSaveMode =
+ PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED;
// Indicates if the native sound trigger service is disabled or not.
// This is an indirect indication of the microphone being open in some other application.
private boolean mServiceDisabled = false;
@@ -205,7 +206,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
int startGenericRecognition(UUID modelId, GenericSoundModel soundModel,
- IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig) {
+ IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
+ boolean runInBatterySaverMode) {
MetricsLogger.count(mContext, "sth_start_recognition", 1);
if (modelId == null || soundModel == null || callback == null ||
recognitionConfig == null) {
@@ -220,7 +222,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return STATUS_ERROR;
}
return startRecognition(soundModel, modelData, callback, recognitionConfig,
- INVALID_VALUE /* keyphraseId */);
+ INVALID_VALUE /* keyphraseId */, runInBatterySaverMode);
}
}
@@ -234,7 +236,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
int startKeyphraseRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
- IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig) {
+ IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
+ boolean runInBatterySaverMode) {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_start_recognition", 1);
if (soundModel == null || callback == null || recognitionConfig == null) {
@@ -244,7 +247,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
if (DBG) {
Slog.d(TAG, "startKeyphraseRecognition for keyphraseId=" + keyphraseId
+ " soundModel=" + soundModel + ", callback=" + callback.asBinder()
- + ", recognitionConfig=" + recognitionConfig);
+ + ", recognitionConfig=" + recognitionConfig
+ + ", runInBatterySaverMode=" + runInBatterySaverMode);
Slog.d(TAG, "moduleProperties=" + mModuleProperties);
dumpModelStateLocked();
}
@@ -273,7 +277,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
return startRecognition(soundModel, model, callback, recognitionConfig,
- keyphraseId);
+ keyphraseId, runInBatterySaverMode);
}
}
@@ -334,7 +338,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
*/
int startRecognition(SoundModel soundModel, ModelData modelData,
IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
- int keyphraseId) {
+ int keyphraseId, boolean runInBatterySaverMode) {
synchronized (mLock) {
if (mModuleProperties == null) {
Slog.w(TAG, "Attempting startRecognition without the capability");
@@ -387,10 +391,11 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
modelData.setCallback(callback);
modelData.setRequested(true);
modelData.setRecognitionConfig(recognitionConfig);
+ modelData.setRunInBatterySaverMode(runInBatterySaverMode);
modelData.setSoundModel(soundModel);
- if (!isRecognitionAllowed()) {
- initializeTelephonyAndPowerStateListeners();
+ if (!isRecognitionAllowedByDeviceState(modelData)) {
+ initializeDeviceStateListeners();
return STATUS_OK;
}
@@ -404,7 +409,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// Initialize power save, call active state monitoring logic.
if (status == STATUS_OK) {
- initializeTelephonyAndPowerStateListeners();
+ initializeDeviceStateListeners();
}
return status;
@@ -519,8 +524,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// Request stop recognition via the update() method.
modelData.setRequested(false);
- int status = updateRecognitionLocked(modelData, isRecognitionAllowed(),
- false /* don't notify for synchronous calls */);
+ int status = updateRecognitionLocked(modelData, false);
if (status != SoundTrigger.STATUS_OK) {
return status;
}
@@ -589,8 +593,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// Stop recognition if it's the current one.
modelData.setRequested(false);
- int status = updateRecognitionLocked(modelData, isRecognitionAllowed(),
- false /* don't notify */);
+ int status = updateRecognitionLocked(modelData, false);
if (status != SoundTrigger.STATUS_OK) {
Slog.w(TAG, "Stop recognition failed for keyphrase ID:" + status);
}
@@ -854,8 +857,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
model.setRequested(config.allowMultipleTriggers);
// TODO: Remove this block if the lower layer supports multiple triggers.
if (model.isRequested()) {
- updateRecognitionLocked(model, isRecognitionAllowed() /* isAllowed */,
- true /* notify */);
+ updateRecognitionLocked(model, true);
}
}
@@ -896,15 +898,16 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return;
}
mCallActive = callActive;
- updateAllRecognitionsLocked(true /* notify */);
+ updateAllRecognitionsLocked();
}
- private void onPowerSaveModeChangedLocked(boolean isPowerSaveMode) {
- if (mIsPowerSaveMode == isPowerSaveMode) {
+ private void onPowerSaveModeChangedLocked(
+ @SoundTriggerPowerSaveMode int soundTriggerPowerSaveMode) {
+ if (mSoundTriggerPowerSaveMode == soundTriggerPowerSaveMode) {
return;
}
- mIsPowerSaveMode = isPowerSaveMode;
- updateAllRecognitionsLocked(true /* notify */);
+ mSoundTriggerPowerSaveMode = soundTriggerPowerSaveMode;
+ updateAllRecognitionsLocked();
}
private void onSoundModelUpdatedLocked(SoundModelEvent event) {
@@ -916,7 +919,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return;
}
mServiceDisabled = disabled;
- updateAllRecognitionsLocked(true /* notify */);
+ updateAllRecognitionsLocked();
}
private void onRecognitionAbortLocked(RecognitionEvent event) {
@@ -997,34 +1000,32 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
// TODO: Remove this block if the lower layer supports multiple triggers.
if (modelData.isRequested()) {
- updateRecognitionLocked(modelData, isRecognitionAllowed(), true /* notify */);
+ updateRecognitionLocked(modelData, true);
}
}
- private void updateAllRecognitionsLocked(boolean notify) {
- boolean isAllowed = isRecognitionAllowed();
+ private void updateAllRecognitionsLocked() {
// updateRecognitionLocked can possibly update the list of models
ArrayList<ModelData> modelDatas = new ArrayList<ModelData>(mModelDataMap.values());
for (ModelData modelData : modelDatas) {
- updateRecognitionLocked(modelData, isAllowed, notify);
+ updateRecognitionLocked(modelData, true);
}
}
- private int updateRecognitionLocked(ModelData model, boolean isAllowed,
- boolean notify) {
- boolean start = model.isRequested() && isAllowed;
- if (start == model.isModelStarted()) {
+ private int updateRecognitionLocked(ModelData model, boolean notifyClientOnError) {
+ boolean shouldStartModel = model.isRequested() && isRecognitionAllowedByDeviceState(model);
+ if (shouldStartModel == model.isModelStarted()) {
// No-op.
return STATUS_OK;
}
- if (start) {
+ if (shouldStartModel) {
int status = prepareForRecognition(model);
if (status != STATUS_OK) {
return status;
}
- return startRecognitionLocked(model, notify);
+ return startRecognitionLocked(model, notifyClientOnError);
} else {
- return stopRecognitionLocked(model, notify);
+ return stopRecognitionLocked(model, notifyClientOnError);
}
}
@@ -1095,11 +1096,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
return;
}
- boolean active = mPowerManager.getPowerSaveState(ServiceType.SOUND)
- .batterySaverEnabled;
- if (DBG) Slog.d(TAG, "onPowerSaveModeChanged: " + active);
+ @SoundTriggerPowerSaveMode int soundTriggerPowerSaveMode =
+ mPowerManager.getSoundTriggerPowerSaveMode();
+ if (DBG) {
+ Slog.d(TAG, "onPowerSaveModeChanged: " + soundTriggerPowerSaveMode);
+ }
synchronized (mLock) {
- onPowerSaveModeChangedLocked(active);
+ onPowerSaveModeChangedLocked(soundTriggerPowerSaveMode);
}
}
}
@@ -1108,14 +1111,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
synchronized (mLock) {
pw.print(" module properties=");
pw.println(mModuleProperties == null ? "null" : mModuleProperties);
-
- pw.print(" call active="); pw.println(mCallActive);
- pw.print(" power save mode active="); pw.println(mIsPowerSaveMode);
- pw.print(" service disabled="); pw.println(mServiceDisabled);
+ pw.print(" call active=");
+ pw.println(mCallActive);
+ pw.println(" SoundTrigger Power State=" + mSoundTriggerPowerSaveMode);
+ pw.print(" service disabled=");
+ pw.println(mServiceDisabled);
}
}
- private void initializeTelephonyAndPowerStateListeners() {
+ private void initializeDeviceStateListeners() {
if (mRecognitionRequested) {
return;
}
@@ -1134,8 +1138,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mContext.registerReceiver(mPowerSaveModeListener,
new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
}
- mIsPowerSaveMode = mPowerManager.getPowerSaveState(ServiceType.SOUND)
- .batterySaverEnabled;
+ mSoundTriggerPowerSaveMode = mPowerManager.getSoundTriggerPowerSaveMode();
mRecognitionRequested = true;
} finally {
@@ -1308,23 +1311,44 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return null;
}
- // Whether we are allowed to run any recognition at all. The conditions that let us run
- // a recognition include: no active phone call or not being in a power save mode. Also,
- // the native service should be enabled.
- private boolean isRecognitionAllowed() {
+ /**
+ * Determines if recognition is allowed at all based on device state
+ *
+ * <p>Depending on the state of the SoundTrigger service, whether a call is active, or if
+ * battery saver mode is enabled, a specific model may or may not be able to run. The result
+ * of this check is not permanent, and the state of the device can change at any time.
+ *
+ * @param modelData Model data to be used for recognition
+ * @return True if recognition is allowed to run at this time. False if not.
+ */
+ private boolean isRecognitionAllowedByDeviceState(ModelData modelData) {
// if mRecognitionRequested is false, call and power state listeners are not registered so
// we read current state directly from services
if (!mRecognitionRequested) {
mCallActive = mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK;
- mIsPowerSaveMode =
- mPowerManager.getPowerSaveState(ServiceType.SOUND).batterySaverEnabled;
+ mSoundTriggerPowerSaveMode = mPowerManager.getSoundTriggerPowerSaveMode();
}
- return !mCallActive && !mServiceDisabled && !mIsPowerSaveMode;
+
+ return !mCallActive && !mServiceDisabled
+ && isRecognitionAllowedByPowerState(
+ modelData);
+ }
+
+ /**
+ * Helper function to validate if a recognition should run based on the current power state
+ *
+ * @param modelData Model data to be used for recognition
+ * @return True if device state allows recognition to run, false if not.
+ */
+ boolean isRecognitionAllowedByPowerState(ModelData modelData) {
+ return mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED
+ || (mSoundTriggerPowerSaveMode == PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY
+ && modelData.shouldRunInBatterySaverMode());
}
// A single routine that implements the start recognition logic for both generic and keyphrase
// models.
- private int startRecognitionLocked(ModelData modelData, boolean notify) {
+ private int startRecognitionLocked(ModelData modelData, boolean notifyClientOnError) {
IRecognitionStatusCallback callback = modelData.getCallback();
RecognitionConfig config = modelData.getRecognitionConfig();
if (callback == null || !modelData.isModelLoaded() || config == null) {
@@ -1334,7 +1358,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return STATUS_ERROR;
}
- if (!isRecognitionAllowed()) {
+ if (!isRecognitionAllowedByDeviceState(modelData)) {
// Nothing to do here.
Slog.w(TAG, "startRecognition requested but not allowed.");
MetricsLogger.count(mContext, "sth_start_recognition_not_allowed", 1);
@@ -1349,7 +1373,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
Slog.w(TAG, "startRecognition failed with " + status);
MetricsLogger.count(mContext, "sth_start_recognition_error", 1);
// Notify of error if needed.
- if (notify) {
+ if (notifyClientOnError) {
try {
callback.onError(status);
} catch (DeadObjectException e) {
@@ -1363,7 +1387,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
MetricsLogger.count(mContext, "sth_start_recognition_success", 1);
modelData.setStarted();
// Notify of resume if needed.
- if (notify) {
+ if (notifyClientOnError) {
try {
callback.onRecognitionResumed();
} catch (DeadObjectException e) {
@@ -1487,6 +1511,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// models.
private int mModelHandle;
+ /**
+ * True if the service should continue listening when battery saver mode is enabled.
+ * Having this flag set requires the client calling
+ * {@link SoundTriggerModule#startRecognition(int, RecognitionConfig)} to be granted
+ * {@link android.Manifest.permission#SOUND_TRIGGER_RUN_IN_BATTERY_SAVER}.
+ */
+ public boolean mRunInBatterySaverMode = false;
+
// The SoundModel instance, one of KeyphraseSoundModel or GenericSoundModel.
private SoundModel mSoundModel = null;
@@ -1562,6 +1594,14 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
mRecognitionConfig = config;
}
+ synchronized void setRunInBatterySaverMode(boolean runInBatterySaverMode) {
+ mRunInBatterySaverMode = runInBatterySaverMode;
+ }
+
+ synchronized boolean shouldRunInBatterySaverMode() {
+ return mRunInBatterySaverMode;
+ }
+
synchronized int getHandle() {
return mModelHandle;
}
@@ -1629,7 +1669,9 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
"ModelState: " + stateToString() + "\n" +
requestedToString() + "\n" +
callbackToString() + "\n" +
- uuidToString() + "\n" + modelTypeToString();
+ uuidToString() + "\n" +
+ modelTypeToString() +
+ "RunInBatterySaverMode=" + mRunInBatterySaverMode;
}
synchronized String modelTypeToString() {
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
index 7cec783fb7c0..7071e23a5ebb 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
@@ -26,7 +26,6 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
-import android.media.permission.Identity;
import android.os.IBinder;
import com.android.server.voiceinteraction.VoiceInteractionManagerService;
@@ -63,10 +62,13 @@ public interface SoundTriggerInternal {
* @param soundModel The sound model to use for recognition.
* @param listener The listener for the recognition events related to the given
* keyphrase.
+ * @param runInBatterySaverMode flag that indicates whether the recognition should continue
+ * after battery saver mode is enabled.
* @return One of {@link #STATUS_ERROR} or {@link #STATUS_OK}.
*/
int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
- IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig);
+ IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig,
+ boolean runInBatterySaverMode);
/**
* Stops recognition for the given {@link Keyphrase} if a recognition is
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index bd678fd54063..7a53f1e159a9 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -296,8 +296,11 @@ public class SoundTriggerService extends SystemService {
@Override
public int startRecognition(ParcelUuid parcelUuid, IRecognitionStatusCallback callback,
- RecognitionConfig config) {
+ RecognitionConfig config, boolean runInBatterySaverMode) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
+ if (runInBatterySaverMode) {
+ enforceCallingPermission(Manifest.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER);
+ }
if (DEBUG) {
Slog.i(TAG, "startRecognition(): Uuid : " + parcelUuid);
}
@@ -316,7 +319,7 @@ public class SoundTriggerService extends SystemService {
}
int ret = mSoundTriggerHelper.startGenericRecognition(parcelUuid.getUuid(), model,
- callback, config);
+ callback, config, runInBatterySaverMode);
if (ret == STATUS_OK) {
mSoundModelStatTracker.onStart(parcelUuid.getUuid());
}
@@ -514,7 +517,7 @@ public class SoundTriggerService extends SystemService {
switch (soundModel.getType()) {
case SoundModel.TYPE_GENERIC_SOUND:
ret = mSoundTriggerHelper.startGenericRecognition(soundModel.getUuid(),
- (GenericSoundModel) soundModel, callback, config);
+ (GenericSoundModel) soundModel, callback, config, false);
break;
default:
Slog.e(TAG, "Unknown model type");
@@ -1505,10 +1508,10 @@ public class SoundTriggerService extends SystemService {
@Override
public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
- IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig) {
+ IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig,
+ boolean runInBatterySaverMode) {
return mSoundTriggerHelper.startKeyphraseRecognition(keyphraseId, soundModel,
- listener,
- recognitionConfig);
+ listener, recognitionConfig, runInBatterySaverMode);
}
@Override
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index ec371bf31160..9f203e1090bd 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1146,7 +1146,8 @@ public class VoiceInteractionManagerService extends SystemService {
@Override
public int startRecognition(int keyphraseId, String bcp47Locale,
- IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig) {
+ IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig,
+ boolean runInBatterySaverMode) {
// Allow the call if this is the current voice interaction service.
synchronized (VoiceInteractionManagerServiceStub.this) {
enforceIsCurrentVoiceInteractionService();
@@ -1154,6 +1155,10 @@ public class VoiceInteractionManagerService extends SystemService {
if (callback == null || recognitionConfig == null || bcp47Locale == null) {
throw new IllegalArgumentException("Illegal argument(s) in startRecognition");
}
+ if (runInBatterySaverMode) {
+ enforceCallingPermission(
+ Manifest.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER);
+ }
}
final int callingUserId = UserHandle.getCallingUserId();
@@ -1173,7 +1178,8 @@ public class VoiceInteractionManagerService extends SystemService {
mLoadedKeyphraseIds.put(keyphraseId, this);
}
return mSession.startRecognition(
- keyphraseId, soundModel, callback, recognitionConfig);
+ keyphraseId, soundModel, callback, recognitionConfig,
+ runInBatterySaverMode);
}
} finally {
Binder.restoreCallingIdentity(caller);