add API for ST clients run in battery saver mode

New system API interface for both SoundTriggerManager and
AlwaysOnHotwordDetector to indicate if a recognition should run in
battery saver mode or not.

Clients supply this information through the existing startRecognition
calls, and the client must hold a new privledged permission,
SOUND_TRIGGER_RUN_IN_BATTERY_SAVER, to indicate this intention.

As a prerequisite, the device PowerManagerService must have the
SoundTrigger service enabled in the battery saver mode battery policy.
If not enabled, recognition will be paused as if the client did not
provide the indication to run in battery saver mode.

Bug: 172294448
Test: build with Google search apk using this feature and verify
recognition keeps running in battery saver mode

Change-Id: Ia43be99290e6fd7c50ff8e4908d6c60ea513b19a
This commit is contained in:
Nicholas Ambur
2020-11-20 15:50:02 -08:00
parent 06c85480ac
commit 28cc6364d6
9 changed files with 151 additions and 72 deletions

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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 {}
@@ -132,6 +133,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}.
*/
@@ -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;
}

View File

@@ -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() {

View File

@@ -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

View File

@@ -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

View File

@@ -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);