diff --git a/core/api/system-current.txt b/core/api/system-current.txt index bd1c5c7f1693a..802e4ab5a7177 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -237,6 +237,7 @@ package android { field public static final String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT"; field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE"; field public static final String SHUTDOWN = "android.permission.SHUTDOWN"; + field public static final String SOUND_TRIGGER_RUN_IN_BATTERY_SAVER = "android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"; field public static final String START_ACTIVITIES_FROM_BACKGROUND = "android.permission.START_ACTIVITIES_FROM_BACKGROUND"; field public static final String START_FOREGROUND_SERVICES_FROM_BACKGROUND = "android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"; field public static final String STATUS_BAR_SERVICE = "android.permission.STATUS_BAR_SERVICE"; @@ -5060,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 { @@ -7870,7 +7872,7 @@ package android.os { method public boolean getDisableAod(); method public boolean getDisableLaunchBoost(); method public boolean getDisableOptionalSensors(); - method public boolean getDisableSoundTrigger(); + method @Deprecated public boolean getDisableSoundTrigger(); method public boolean getDisableVibration(); method public boolean getEnableAdjustBrightness(); method public boolean getEnableDataSaver(); @@ -7880,6 +7882,7 @@ package android.os { method public boolean getForceAllAppsStandby(); method public boolean getForceBackgroundCheck(); method public int getLocationMode(); + method public int getSoundTriggerMode(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; } @@ -7896,7 +7899,7 @@ package android.os { method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableAod(boolean); method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableLaunchBoost(boolean); method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableOptionalSensors(boolean); - method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableSoundTrigger(boolean); + method @Deprecated @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableSoundTrigger(boolean); method @NonNull public android.os.BatterySaverPolicyConfig.Builder setDisableVibration(boolean); method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableAdjustBrightness(boolean); method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableDataSaver(boolean); @@ -7906,6 +7909,7 @@ package android.os { method @NonNull public android.os.BatterySaverPolicyConfig.Builder setForceAllAppsStandby(boolean); method @NonNull public android.os.BatterySaverPolicyConfig.Builder setForceBackgroundCheck(boolean); method @NonNull public android.os.BatterySaverPolicyConfig.Builder setLocationMode(int); + method @NonNull public android.os.BatterySaverPolicyConfig.Builder setSoundTriggerMode(int); } public final class BatteryStatsManager { @@ -8266,6 +8270,9 @@ package android.os { field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1 field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0 field public static final String REBOOT_USERSPACE = "userspace"; + field public static final int SOUND_TRIGGER_MODE_ALL_DISABLED = 2; // 0x2 + field public static final int SOUND_TRIGGER_MODE_ALL_ENABLED = 0; // 0x0 + field public static final int SOUND_TRIGGER_MODE_CRITICAL_ONLY = 1; // 0x1 field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3 field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1 field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0 @@ -10198,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/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java index 3f6ce4fa807c9..6f5139038e866 100644 --- a/core/java/android/os/BatterySaverPolicyConfig.java +++ b/core/java/android/os/BatterySaverPolicyConfig.java @@ -42,7 +42,6 @@ public final class BatterySaverPolicyConfig implements Parcelable { private final boolean mDisableAod; private final boolean mDisableLaunchBoost; private final boolean mDisableOptionalSensors; - private final boolean mDisableSoundTrigger; private final boolean mDisableVibration; private final boolean mEnableAdjustBrightness; private final boolean mEnableDataSaver; @@ -52,6 +51,7 @@ public final class BatterySaverPolicyConfig implements Parcelable { private final boolean mForceAllAppsStandby; private final boolean mForceBackgroundCheck; private final int mLocationMode; + private final int mSoundTriggerMode; private BatterySaverPolicyConfig(Builder in) { mAdjustBrightnessFactor = Math.max(0, Math.min(in.mAdjustBrightnessFactor, 1f)); @@ -64,7 +64,6 @@ public final class BatterySaverPolicyConfig implements Parcelable { mDisableAod = in.mDisableAod; mDisableLaunchBoost = in.mDisableLaunchBoost; mDisableOptionalSensors = in.mDisableOptionalSensors; - mDisableSoundTrigger = in.mDisableSoundTrigger; mDisableVibration = in.mDisableVibration; mEnableAdjustBrightness = in.mEnableAdjustBrightness; mEnableDataSaver = in.mEnableDataSaver; @@ -75,6 +74,8 @@ public final class BatterySaverPolicyConfig implements Parcelable { mForceBackgroundCheck = in.mForceBackgroundCheck; mLocationMode = Math.max(PowerManager.MIN_LOCATION_MODE, Math.min(in.mLocationMode, PowerManager.MAX_LOCATION_MODE)); + mSoundTriggerMode = Math.max(PowerManager.MIN_SOUND_TRIGGER_MODE, + Math.min(in.mSoundTriggerMode, PowerManager.MAX_SOUND_TRIGGER_MODE)); } private BatterySaverPolicyConfig(Parcel in) { @@ -99,7 +100,6 @@ public final class BatterySaverPolicyConfig implements Parcelable { mDisableAod = in.readBoolean(); mDisableLaunchBoost = in.readBoolean(); mDisableOptionalSensors = in.readBoolean(); - mDisableSoundTrigger = in.readBoolean(); mDisableVibration = in.readBoolean(); mEnableAdjustBrightness = in.readBoolean(); mEnableDataSaver = in.readBoolean(); @@ -110,6 +110,8 @@ public final class BatterySaverPolicyConfig implements Parcelable { mForceBackgroundCheck = in.readBoolean(); mLocationMode = Math.max(PowerManager.MIN_LOCATION_MODE, Math.min(in.readInt(), PowerManager.MAX_LOCATION_MODE)); + mSoundTriggerMode = Math.max(PowerManager.MIN_SOUND_TRIGGER_MODE, + Math.min(in.readInt(), PowerManager.MAX_SOUND_TRIGGER_MODE)); } public static final @android.annotation.NonNull Creator CREATOR = @@ -149,7 +151,6 @@ public final class BatterySaverPolicyConfig implements Parcelable { dest.writeBoolean(mDisableAod); dest.writeBoolean(mDisableLaunchBoost); dest.writeBoolean(mDisableOptionalSensors); - dest.writeBoolean(mDisableSoundTrigger); dest.writeBoolean(mDisableVibration); dest.writeBoolean(mEnableAdjustBrightness); dest.writeBoolean(mEnableDataSaver); @@ -159,6 +160,7 @@ public final class BatterySaverPolicyConfig implements Parcelable { dest.writeBoolean(mForceAllAppsStandby); dest.writeBoolean(mForceBackgroundCheck); dest.writeInt(mLocationMode); + dest.writeInt(mSoundTriggerMode); } @NonNull @@ -184,7 +186,7 @@ public final class BatterySaverPolicyConfig implements Parcelable { + "launch_boost_disabled=" + mDisableLaunchBoost + "," + "optional_sensors_disabled=" + mDisableOptionalSensors + "," + "quick_doze_enabled=" + mEnableQuickDoze + "," - + "soundtrigger_disabled=" + mDisableSoundTrigger + "," + + "soundtrigger_mode=" + mSoundTriggerMode + "," + "vibration_disabled=" + mDisableVibration + "," + sb.toString(); } @@ -242,12 +244,21 @@ public final class BatterySaverPolicyConfig implements Parcelable { return mDisableOptionalSensors; } + /** + * Get the SoundTrigger mode while in Battery Saver. + */ + public int getSoundTriggerMode() { + return mSoundTriggerMode; + } + /** * Whether or not to disable {@link android.hardware.soundtrigger.SoundTrigger} * while in Battery Saver. + * @deprecated Use {@link #getSoundTriggerMode()} instead. */ + @Deprecated public boolean getDisableSoundTrigger() { - return mDisableSoundTrigger; + return mSoundTriggerMode == PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED; } /** Whether or not to disable vibration while in Battery Saver. */ @@ -315,7 +326,6 @@ public final class BatterySaverPolicyConfig implements Parcelable { private boolean mDisableAod = false; private boolean mDisableLaunchBoost = false; private boolean mDisableOptionalSensors = false; - private boolean mDisableSoundTrigger = false; private boolean mDisableVibration = false; private boolean mEnableAdjustBrightness = false; private boolean mEnableDataSaver = false; @@ -325,6 +335,7 @@ public final class BatterySaverPolicyConfig implements Parcelable { private boolean mForceAllAppsStandby = false; private boolean mForceBackgroundCheck = false; private int mLocationMode = PowerManager.LOCATION_MODE_NO_CHANGE; + private int mSoundTriggerMode = PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED; public Builder() { } @@ -416,10 +427,26 @@ public final class BatterySaverPolicyConfig implements Parcelable { /** * Set whether or not to disable {@link android.hardware.soundtrigger.SoundTrigger} * while in Battery Saver. + * @deprecated Use {@link #setSoundTriggerMode(int)} instead. */ + @Deprecated @NonNull public Builder setDisableSoundTrigger(boolean disableSoundTrigger) { - mDisableSoundTrigger = disableSoundTrigger; + if (disableSoundTrigger) { + mSoundTriggerMode = PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED; + } else { + mSoundTriggerMode = PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED; + } + return this; + } + + /** + * Set the SoundTrigger mode while in Battery Saver. + */ + @NonNull + public Builder setSoundTriggerMode( + @PowerManager.SoundTriggerPowerSaveMode int soundTriggerMode) { + mSoundTriggerMode = soundTriggerMode; return this; } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index d11f3ce0d1123..90648325ae0ea 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -885,6 +885,45 @@ public final class PowerManager { }) public @interface LocationPowerSaveMode {} + /** + * In this mode, all active SoundTrigger recognitions are enabled by the SoundTrigger system + * service. + * @hide + */ + @SystemApi + public static final int SOUND_TRIGGER_MODE_ALL_ENABLED = 0; + /** + * In this mode, only privileged components of the SoundTrigger system service should be + * enabled. This functionality is to be used to limit SoundTrigger recognitions to those only + * deemed necessary by the system. + * @hide + */ + @SystemApi + public static final int SOUND_TRIGGER_MODE_CRITICAL_ONLY = 1; + /** + * In this mode, all active SoundTrigger recognitions should be disabled by the SoundTrigger + * system service. + * @hide + */ + @SystemApi + public static final int SOUND_TRIGGER_MODE_ALL_DISABLED = 2; + + /** @hide */ + public static final int MIN_SOUND_TRIGGER_MODE = SOUND_TRIGGER_MODE_ALL_ENABLED; + /** @hide */ + public static final int MAX_SOUND_TRIGGER_MODE = SOUND_TRIGGER_MODE_ALL_DISABLED; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"SOUND_TRIGGER_MODE_"}, value = { + SOUND_TRIGGER_MODE_ALL_ENABLED, + SOUND_TRIGGER_MODE_CRITICAL_ONLY, + SOUND_TRIGGER_MODE_ALL_DISABLED, + }) + public @interface SoundTriggerPowerSaveMode {} + /** @hide */ public static String locationPowerSaveModeToString(@LocationPowerSaveMode int mode) { switch (mode) { @@ -1832,6 +1871,26 @@ public final class PowerManager { return powerSaveState.locationMode; } + /** + * Returns how SoundTrigger features should behave when battery saver is on. When battery saver + * is off, this will always return {@link #SOUND_TRIGGER_MODE_ALL_ENABLED}. + * + *

This API is normally only useful for components that provide use SoundTrigger features. + * + * @see #isPowerSaveMode() + * @see #ACTION_POWER_SAVE_MODE_CHANGED + * + * @hide + */ + @SoundTriggerPowerSaveMode + public int getSoundTriggerPowerSaveMode() { + final PowerSaveState powerSaveState = getPowerSaveState(ServiceType.SOUND); + if (!powerSaveState.batterySaverEnabled) { + return SOUND_TRIGGER_MODE_ALL_ENABLED; + } + return powerSaveState.soundTriggerMode; + } + /** * Returns true if the device is currently in idle mode. This happens when a device * has been sitting unused and unmoving for a sufficiently long period of time, so that diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java index 4a5e89479ec04..7d3cd0687180c 100644 --- a/core/java/android/os/PowerSaveState.java +++ b/core/java/android/os/PowerSaveState.java @@ -36,11 +36,13 @@ public class PowerSaveState implements Parcelable { */ public final boolean globalBatterySaverEnabled; public final int locationMode; + public final int soundTriggerMode; public final float brightnessFactor; public PowerSaveState(Builder builder) { batterySaverEnabled = builder.mBatterySaverEnabled; locationMode = builder.mLocationMode; + soundTriggerMode = builder.mSoundTriggerMode; brightnessFactor = builder.mBrightnessFactor; globalBatterySaverEnabled = builder.mGlobalBatterySaverEnabled; } @@ -49,6 +51,7 @@ public class PowerSaveState implements Parcelable { batterySaverEnabled = in.readByte() != 0; globalBatterySaverEnabled = in.readByte() != 0; locationMode = in.readInt(); + soundTriggerMode = in.readInt(); brightnessFactor = in.readFloat(); } @@ -62,6 +65,7 @@ public class PowerSaveState implements Parcelable { dest.writeByte((byte) (batterySaverEnabled ? 1 : 0)); dest.writeByte((byte) (globalBatterySaverEnabled ? 1 : 0)); dest.writeInt(locationMode); + dest.writeInt(soundTriggerMode); dest.writeFloat(brightnessFactor); } @@ -69,6 +73,7 @@ public class PowerSaveState implements Parcelable { private boolean mBatterySaverEnabled = false; private boolean mGlobalBatterySaverEnabled = false; private int mLocationMode = 0; + private int mSoundTriggerMode = PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED; private float mBrightnessFactor = 0.5f; public Builder() {} @@ -83,6 +88,11 @@ public class PowerSaveState implements Parcelable { return this; } + public Builder setSoundTriggerMode(int mode) { + mSoundTriggerMode = mode; + return this; + } + public Builder setLocationMode(int mode) { mLocationMode = mode; return this; diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index e934fa483ebe1..117b769d64051 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 ec7d282522c8b..a1ba558a5e7fb 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 33aab4132150d..6149260726016 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/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f543373a35a14..4410bee2fbab7 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5034,6 +5034,13 @@ + + + diff --git a/core/tests/coretests/jni/NativePowerManagerTest.cpp b/core/tests/coretests/jni/NativePowerManagerTest.cpp index 50fb31ba085ad..5f20e4f9c4074 100644 --- a/core/tests/coretests/jni/NativePowerManagerTest.cpp +++ b/core/tests/coretests/jni/NativePowerManagerTest.cpp @@ -61,7 +61,6 @@ static struct BatterySaverPolicyConfigFieldId { jfieldID disableAod; jfieldID disableLaunchBoost; jfieldID disableOptionalSensors; - jfieldID disableSoundTrigger; jfieldID disableVibration; jfieldID enableAdjustBrightness; jfieldID enableDataSaver; @@ -71,6 +70,7 @@ static struct BatterySaverPolicyConfigFieldId { jfieldID forceAllAppsStandby; jfieldID forceBackgroundCheck; jfieldID locationMode; + jfieldID soundTriggerMode; } gBSPCFieldIds; static jobject nativeObtainParcel(JNIEnv* env) { @@ -171,10 +171,11 @@ static void nativeUnparcelAndVerifyWorkSource(JNIEnv* env, jobject /* obj */, jo static jobject nativeObtainPowerSaveStateParcel(JNIEnv* env, jobject /* obj */, jboolean batterySaverEnabled, jboolean globalBatterySaverEnabled, - jint locationMode, jfloat brightnessFactor) { + jint locationMode, jint soundTriggerMode, jfloat brightnessFactor) { PowerSaveState ps = PowerSaveState(static_cast(batterySaverEnabled), static_cast(globalBatterySaverEnabled), static_cast(locationMode), + static_cast(soundTriggerMode), static_cast(brightnessFactor)); jobject psParcel = nativeObtainParcel(env); Parcel* parcel = nativeGetParcelData(env, psParcel); @@ -189,7 +190,7 @@ static jobject nativeObtainPowerSaveStateParcel(JNIEnv* env, jobject /* obj */, static void nativeUnparcelAndVerifyPowerSaveState(JNIEnv* env, jobject /* obj */, jobject psParcel, jboolean batterySaverEnabled, jboolean globalBatterySaverEnabled, - jint locationMode, jfloat brightnessFactor) { + jint locationMode, jint soundTriggerMode, jfloat brightnessFactor) { PowerSaveState ps = {}; Parcel* parcel = nativeGetParcelData(env, psParcel); status_t err = ps.readFromParcel(parcel); @@ -200,6 +201,7 @@ static void nativeUnparcelAndVerifyPowerSaveState(JNIEnv* env, jobject /* obj */ PowerSaveState psOrig = PowerSaveState(static_cast(batterySaverEnabled), static_cast(globalBatterySaverEnabled), static_cast(locationMode), + static_cast(soundTriggerMode), static_cast(brightnessFactor)); if (ps == psOrig) { return; @@ -229,7 +231,6 @@ static jobject nativeObtainBSPConfigParcel(JNIEnv* env, jobject /* obj */, env->GetBooleanField(bsObj, gBSPCFieldIds.disableAod), env->GetBooleanField(bsObj, gBSPCFieldIds.disableLaunchBoost), env->GetBooleanField(bsObj, gBSPCFieldIds.disableOptionalSensors), - env->GetBooleanField(bsObj, gBSPCFieldIds.disableSoundTrigger), env->GetBooleanField(bsObj, gBSPCFieldIds.disableVibration), env->GetBooleanField(bsObj, gBSPCFieldIds.enableAdjustBrightness), env->GetBooleanField(bsObj, gBSPCFieldIds.enableDataSaver), @@ -238,7 +239,8 @@ static jobject nativeObtainBSPConfigParcel(JNIEnv* env, jobject /* obj */, env->GetBooleanField(bsObj, gBSPCFieldIds.enableQuickDoze), env->GetBooleanField(bsObj, gBSPCFieldIds.forceAllAppsStandby), env->GetBooleanField(bsObj, gBSPCFieldIds.forceBackgroundCheck), - static_cast(env->GetIntField(bsObj, gBSPCFieldIds.locationMode))); + static_cast(env->GetIntField(bsObj, gBSPCFieldIds.locationMode)), + static_cast(env->GetIntField(bsObj, gBSPCFieldIds.soundTriggerMode))); jobject bsParcel = nativeObtainParcel(env); Parcel* parcel = nativeGetParcelData(env, bsParcel); @@ -279,7 +281,6 @@ static void nativeUnparcelAndVerifyBSPConfig(JNIEnv* env, jobject /* obj */, env->GetBooleanField(bsObj, gBSPCFieldIds.disableAod), env->GetBooleanField(bsObj, gBSPCFieldIds.disableLaunchBoost), env->GetBooleanField(bsObj, gBSPCFieldIds.disableOptionalSensors), - env->GetBooleanField(bsObj, gBSPCFieldIds.disableSoundTrigger), env->GetBooleanField(bsObj, gBSPCFieldIds.disableVibration), env->GetBooleanField(bsObj, gBSPCFieldIds.enableAdjustBrightness), env->GetBooleanField(bsObj, gBSPCFieldIds.enableDataSaver), @@ -288,7 +289,8 @@ static void nativeUnparcelAndVerifyBSPConfig(JNIEnv* env, jobject /* obj */, env->GetBooleanField(bsObj, gBSPCFieldIds.enableQuickDoze), env->GetBooleanField(bsObj, gBSPCFieldIds.forceAllAppsStandby), env->GetBooleanField(bsObj, gBSPCFieldIds.forceBackgroundCheck), - static_cast(env->GetIntField(bsObj, gBSPCFieldIds.locationMode))); + static_cast(env->GetIntField(bsObj, gBSPCFieldIds.locationMode)), + static_cast(env->GetIntField(bsObj, gBSPCFieldIds.soundTriggerMode))); if (bs == bsOrig) { return; @@ -307,9 +309,9 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) (void*) nativeObtainWorkSourceParcel }, { "nativeUnparcelAndVerifyWorkSource", "(Landroid/os/Parcel;[I[Ljava/lang/String;)V", (void*) nativeUnparcelAndVerifyWorkSource }, - { "nativeObtainPowerSaveStateParcel", "(ZZIF)Landroid/os/Parcel;", + { "nativeObtainPowerSaveStateParcel", "(ZZIIF)Landroid/os/Parcel;", (void*) nativeObtainPowerSaveStateParcel }, - { "nativeUnparcelAndVerifyPowerSaveState", "(Landroid/os/Parcel;ZZIF)V", + { "nativeUnparcelAndVerifyPowerSaveState", "(Landroid/os/Parcel;ZZIIF)V", (void*) nativeUnparcelAndVerifyPowerSaveState }, { "nativeObtainBSPConfigParcel", "(Landroid/os/BatterySaverPolicyConfig;" @@ -340,7 +342,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) GET_FIELD_ID(gBSPCFieldIds.disableAod, bspcClazz, "mDisableAod", "Z"); GET_FIELD_ID(gBSPCFieldIds.disableLaunchBoost, bspcClazz, "mDisableLaunchBoost", "Z"); GET_FIELD_ID(gBSPCFieldIds.disableOptionalSensors, bspcClazz, "mDisableOptionalSensors", "Z"); - GET_FIELD_ID(gBSPCFieldIds.disableSoundTrigger, bspcClazz, "mDisableSoundTrigger", "Z"); GET_FIELD_ID(gBSPCFieldIds.disableVibration, bspcClazz, "mDisableVibration", "Z"); GET_FIELD_ID(gBSPCFieldIds.enableAdjustBrightness, bspcClazz, "mEnableAdjustBrightness", "Z"); GET_FIELD_ID(gBSPCFieldIds.enableDataSaver, bspcClazz, "mEnableDataSaver", "Z"); @@ -350,6 +351,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) GET_FIELD_ID(gBSPCFieldIds.forceAllAppsStandby, bspcClazz, "mForceAllAppsStandby", "Z"); GET_FIELD_ID(gBSPCFieldIds.forceBackgroundCheck, bspcClazz, "mForceBackgroundCheck", "Z"); GET_FIELD_ID(gBSPCFieldIds.locationMode, bspcClazz, "mLocationMode", "I"); + GET_FIELD_ID(gBSPCFieldIds.soundTriggerMode, bspcClazz, "mSoundTriggerMode", "I"); jniRegisterNativeMethods(env, "android/os/PowerManagerTest", methodTable, sizeof(methodTable) / sizeof(JNINativeMethod)); diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java index d3baed34509ea..0dfc37131f7f8 100644 --- a/core/tests/coretests/src/android/os/PowerManagerTest.java +++ b/core/tests/coretests/src/android/os/PowerManagerTest.java @@ -53,10 +53,11 @@ public class PowerManagerTest extends AndroidTestCase { private native void nativeUnparcelAndVerifyWorkSource(Parcel parcel, int[] uids, String[] names); private native Parcel nativeObtainPowerSaveStateParcel(boolean batterySaverEnabled, - boolean globalBatterySaverEnabled, int locationMode, float brightnessFactor); + boolean globalBatterySaverEnabled, int locationMode, int soundTriggerMode, + float brightnessFactor); private native void nativeUnparcelAndVerifyPowerSaveState(Parcel parcel, boolean batterySaverEnabled, boolean globalBatterySaverEnabled, - int locationMode, float brightnessFactor); + int locationMode, int soundTriggerMode, float brightnessFactor); private native Parcel nativeObtainBSPConfigParcel(BatterySaverPolicyConfig bs, String[] keys, String[] values); private native void nativeUnparcelAndVerifyBSPConfig(Parcel parcel, BatterySaverPolicyConfig bs, @@ -351,15 +352,17 @@ public class PowerManagerTest extends AndroidTestCase { * specified parameters, and verify the PowerSaveState object created from the parcel. */ private void unparcelPowerSaveStateFromNativeAndVerify(boolean batterySaverEnabled, - boolean globalBatterySaverEnabled, int locationMode, float brightnessFactor) { + boolean globalBatterySaverEnabled, int locationMode, int soundTriggerMode, + float brightnessFactor) { // Obtain PowerSaveState as parcel from native, with parameters. Parcel psParcel = nativeObtainPowerSaveStateParcel(batterySaverEnabled, - globalBatterySaverEnabled, locationMode, brightnessFactor); + globalBatterySaverEnabled, locationMode, soundTriggerMode, brightnessFactor); // Verify the parcel. PowerSaveState ps = PowerSaveState.CREATOR.createFromParcel(psParcel); assertEquals(ps.batterySaverEnabled, batterySaverEnabled); assertEquals(ps.globalBatterySaverEnabled, globalBatterySaverEnabled); assertEquals(ps.locationMode, locationMode); + assertEquals(ps.soundTriggerMode, soundTriggerMode); assertEquals(ps.brightnessFactor, brightnessFactor, 0.01f); } @@ -368,7 +371,8 @@ public class PowerManagerTest extends AndroidTestCase { * specified parameters. Native will verify the PowerSaveState in native is expected. */ private void parcelPowerSaveStateToNativeAndVerify(boolean batterySaverEnabled, - boolean globalBatterySaverEnabled, int locationMode, float brightnessFactor) { + boolean globalBatterySaverEnabled, int locationMode, int soundTriggerMode, + float brightnessFactor) { Parcel psParcel = Parcel.obtain(); // PowerSaveState API blocks Builder.build(), generate a parcel instead of object. PowerSaveState ps = new PowerSaveState.Builder() @@ -380,7 +384,7 @@ public class PowerManagerTest extends AndroidTestCase { psParcel.setDataPosition(0); //Set the PowerSaveState as parcel to native and verify in native space. nativeUnparcelAndVerifyPowerSaveState(psParcel, batterySaverEnabled, - globalBatterySaverEnabled, locationMode, brightnessFactor); + globalBatterySaverEnabled, locationMode, soundTriggerMode, brightnessFactor); } /** @@ -463,10 +467,13 @@ public class PowerManagerTest extends AndroidTestCase { public void testPowerSaveStateNativeToJava() { unparcelPowerSaveStateFromNativeAndVerify(false /* batterySaverEnabled */, false /* globalBatterySaverEnabled */, - PowerManager.LOCATION_MODE_FOREGROUND_ONLY, 0.3f /* brightnessFactor */); + PowerManager.LOCATION_MODE_FOREGROUND_ONLY, + PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY, + 0.3f /* brightnessFactor */); unparcelPowerSaveStateFromNativeAndVerify(true /* batterySaverEnabled */, true /* globalBatterySaverEnabled */, PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF, + PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED, 0.5f /* brightnessFactor */); } @@ -479,10 +486,13 @@ public class PowerManagerTest extends AndroidTestCase { public void testSetPowerSaveStateJavaToNative() { parcelPowerSaveStateToNativeAndVerify(false /* batterySaverEnabled */, false /* globalBatterySaverEnabled */, - PowerManager.LOCATION_MODE_FOREGROUND_ONLY, 0.3f /* brightnessFactor */); + PowerManager.LOCATION_MODE_FOREGROUND_ONLY, + PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY, + 0.3f /* brightnessFactor */); parcelPowerSaveStateToNativeAndVerify(true /* batterySaverEnabled */, true /* globalBatterySaverEnabled */, PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF, + PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED, 0.5f /* brightnessFactor */); } diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java index 0a1eefae59d6b..d9c8a240fa1a1 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 {} @@ -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; } diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java index eea79f6eca958..ff50ebd07f54e 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java @@ -72,7 +72,7 @@ public class BatterySaverPolicy extends ContentObserver implements @VisibleForTesting static final String KEY_DISABLE_ANIMATION = "disable_animation"; @VisibleForTesting - static final String KEY_DISABLE_SOUNDTRIGGER = "disable_soundtrigger"; + static final String KEY_SOUNDTRIGGER_MODE = "soundtrigger_mode"; /** * Turn on the network firewall when Battery Saver is turned on. @@ -144,7 +144,6 @@ public class BatterySaverPolicy extends ContentObserver implements false, /* disableAod */ false, /* disableLaunchBoost */ false, /* disableOptionalSensors */ - false, /* disableSoundTrigger */ false, /* disableVibration */ false, /* enableAdjustBrightness */ false, /* enableDataSaver */ @@ -155,7 +154,8 @@ public class BatterySaverPolicy extends ContentObserver implements new ArrayMap<>(), /* filesForNoninteractive */ false, /* forceAllAppsStandby */ false, /* forceBackgroundCheck */ - PowerManager.LOCATION_MODE_NO_CHANGE /* locationMode */ + PowerManager.LOCATION_MODE_NO_CHANGE, /* locationMode */ + PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED /* soundTriggerMode */ ); private static final Policy DEFAULT_ADAPTIVE_POLICY = OFF_POLICY; @@ -169,7 +169,6 @@ public class BatterySaverPolicy extends ContentObserver implements true, /* disableAod */ true, /* disableLaunchBoost */ true, /* disableOptionalSensors */ - true, /* disableSoundTrigger */ true, /* disableVibration */ false, /* enableAdjustBrightness */ false, /* enableDataSaver */ @@ -180,7 +179,8 @@ public class BatterySaverPolicy extends ContentObserver implements new ArrayMap<>(), /* filesForNoninteractive */ true, /* forceAllAppsStandby */ true, /* forceBackgroundCheck */ - PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF /* locationMode */ + PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF, /* locationMode */ + PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY /* soundTriggerMode */ ); private final Object mLock; @@ -494,7 +494,6 @@ public class BatterySaverPolicy extends ContentObserver implements rawPolicy.disableAod, rawPolicy.disableLaunchBoost, rawPolicy.disableOptionalSensors, - rawPolicy.disableSoundTrigger, // Don't disable vibration when accessibility is on. rawPolicy.disableVibration && !mAccessibilityEnabled.get(), rawPolicy.enableAdjustBrightness, @@ -507,7 +506,8 @@ public class BatterySaverPolicy extends ContentObserver implements rawPolicy.filesForNoninteractive, rawPolicy.forceAllAppsStandby, rawPolicy.forceBackgroundCheck, - locationMode + locationMode, + rawPolicy.soundTriggerMode ); @@ -518,7 +518,9 @@ public class BatterySaverPolicy extends ContentObserver implements if (mEffectivePolicyRaw.disableVibration) sb.append("v"); if (mEffectivePolicyRaw.disableAnimation) sb.append("a"); - if (mEffectivePolicyRaw.disableSoundTrigger) sb.append("s"); + + sb.append(mEffectivePolicyRaw.soundTriggerMode); + if (mEffectivePolicyRaw.deferFullBackup) sb.append("F"); if (mEffectivePolicyRaw.deferKeyValueBackup) sb.append("K"); if (mEffectivePolicyRaw.enableFirewall) sb.append("f"); @@ -599,9 +601,9 @@ public class BatterySaverPolicy extends ContentObserver implements * in battery saver mode. * * @see Settings.Global#BATTERY_SAVER_CONSTANTS - * @see #KEY_DISABLE_SOUNDTRIGGER + * @see #KEY_SOUNDTRIGGER_MODE */ - public final boolean disableSoundTrigger; + public final int soundTriggerMode; /** * {@code true} if vibration is disabled in battery saver mode. @@ -692,7 +694,6 @@ public class BatterySaverPolicy extends ContentObserver implements boolean disableAod, boolean disableLaunchBoost, boolean disableOptionalSensors, - boolean disableSoundTrigger, boolean disableVibration, boolean enableAdjustBrightness, boolean enableDataSaver, @@ -703,7 +704,8 @@ public class BatterySaverPolicy extends ContentObserver implements ArrayMap filesForNoninteractive, boolean forceAllAppsStandby, boolean forceBackgroundCheck, - int locationMode) { + int locationMode, + int soundTriggerMode) { this.adjustBrightnessFactor = Math.min(1, Math.max(0, adjustBrightnessFactor)); this.advertiseIsEnabled = advertiseIsEnabled; @@ -713,7 +715,6 @@ public class BatterySaverPolicy extends ContentObserver implements this.disableAod = disableAod; this.disableLaunchBoost = disableLaunchBoost; this.disableOptionalSensors = disableOptionalSensors; - this.disableSoundTrigger = disableSoundTrigger; this.disableVibration = disableVibration; this.enableAdjustBrightness = enableAdjustBrightness; this.enableDataSaver = enableDataSaver; @@ -733,6 +734,14 @@ public class BatterySaverPolicy extends ContentObserver implements this.locationMode = locationMode; } + if (soundTriggerMode < PowerManager.MIN_SOUND_TRIGGER_MODE + || soundTriggerMode > PowerManager.MAX_SOUND_TRIGGER_MODE) { + Slog.e(TAG, "Invalid SoundTrigger mode: " + soundTriggerMode); + this.soundTriggerMode = PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED; + } else { + this.soundTriggerMode = soundTriggerMode; + } + mHashCode = Objects.hash( adjustBrightnessFactor, advertiseIsEnabled, @@ -742,7 +751,6 @@ public class BatterySaverPolicy extends ContentObserver implements disableAod, disableLaunchBoost, disableOptionalSensors, - disableSoundTrigger, disableVibration, enableAdjustBrightness, enableDataSaver, @@ -753,7 +761,8 @@ public class BatterySaverPolicy extends ContentObserver implements filesForNoninteractive, forceAllAppsStandby, forceBackgroundCheck, - locationMode); + locationMode, + soundTriggerMode); } static Policy fromConfig(BatterySaverPolicyConfig config) { @@ -778,7 +787,6 @@ public class BatterySaverPolicy extends ContentObserver implements config.getDisableAod(), config.getDisableLaunchBoost(), config.getDisableOptionalSensors(), - config.getDisableSoundTrigger(), config.getDisableVibration(), config.getEnableAdjustBrightness(), config.getEnableDataSaver(), @@ -791,7 +799,8 @@ public class BatterySaverPolicy extends ContentObserver implements (new CpuFrequencies()).parseString(cpuFreqNoninteractive).toSysFileMap(), config.getForceAllAppsStandby(), config.getForceBackgroundCheck(), - config.getLocationMode() + config.getLocationMode(), + config.getSoundTriggerMode() ); } @@ -851,9 +860,6 @@ public class BatterySaverPolicy extends ContentObserver implements final boolean disableOptionalSensors = parser.getBoolean(KEY_DISABLE_OPTIONAL_SENSORS, properties.getBoolean(KEY_DISABLE_OPTIONAL_SENSORS + configSuffix, defaultPolicy.disableOptionalSensors)); - final boolean disableSoundTrigger = parser.getBoolean(KEY_DISABLE_SOUNDTRIGGER, - properties.getBoolean(KEY_DISABLE_SOUNDTRIGGER + configSuffix, - defaultPolicy.disableSoundTrigger)); final boolean disableVibrationConfig = parser.getBoolean(KEY_DISABLE_VIBRATION, properties.getBoolean(KEY_DISABLE_VIBRATION + configSuffix, defaultPolicy.disableVibration)); @@ -882,7 +888,9 @@ public class BatterySaverPolicy extends ContentObserver implements final int locationMode = parser.getInt(KEY_LOCATION_MODE, properties.getInt(KEY_LOCATION_MODE + configSuffix, defaultPolicy.locationMode)); - + final int soundTriggerMode = parser.getInt(KEY_SOUNDTRIGGER_MODE, + properties.getInt(KEY_SOUNDTRIGGER_MODE + configSuffix, + defaultPolicy.soundTriggerMode)); return new Policy( adjustBrightnessFactor, advertiseIsEnabled, @@ -892,7 +900,6 @@ public class BatterySaverPolicy extends ContentObserver implements disableAod, disableLaunchBoost, disableOptionalSensors, - disableSoundTrigger, /* disableVibration */ disableVibrationConfig, enableBrightnessAdjustment, @@ -906,7 +913,8 @@ public class BatterySaverPolicy extends ContentObserver implements (new CpuFrequencies()).parseString(cpuFreqNoninteractive).toSysFileMap(), forceAllAppsStandby, forceBackgroundCheck, - locationMode + locationMode, + soundTriggerMode ); } @@ -923,7 +931,6 @@ public class BatterySaverPolicy extends ContentObserver implements && disableAod == other.disableAod && disableLaunchBoost == other.disableLaunchBoost && disableOptionalSensors == other.disableOptionalSensors - && disableSoundTrigger == other.disableSoundTrigger && disableVibration == other.disableVibration && enableAdjustBrightness == other.enableAdjustBrightness && enableDataSaver == other.enableDataSaver @@ -933,6 +940,7 @@ public class BatterySaverPolicy extends ContentObserver implements && forceAllAppsStandby == other.forceAllAppsStandby && forceBackgroundCheck == other.forceBackgroundCheck && locationMode == other.locationMode + && soundTriggerMode == other.soundTriggerMode && filesForInteractive.equals(other.filesForInteractive) && filesForNoninteractive.equals(other.filesForNoninteractive); } @@ -983,7 +991,11 @@ public class BatterySaverPolicy extends ContentObserver implements return builder.setBatterySaverEnabled(currPolicy.enableDataSaver) .build(); case ServiceType.SOUND: - return builder.setBatterySaverEnabled(currPolicy.disableSoundTrigger) + boolean soundTriggerBatterySaverEnabled = currPolicy.advertiseIsEnabled + || currPolicy.soundTriggerMode + != PowerManager.SOUND_TRIGGER_MODE_ALL_ENABLED; + return builder.setBatterySaverEnabled(soundTriggerBatterySaverEnabled) + .setSoundTriggerMode(currPolicy.soundTriggerMode) .build(); case ServiceType.VIBRATION: return builder.setBatterySaverEnabled(currPolicy.disableVibration) @@ -1172,7 +1184,7 @@ public class BatterySaverPolicy extends ContentObserver implements pw.println(KEY_FORCE_BACKGROUND_CHECK + "=" + p.forceBackgroundCheck); pw.println(KEY_DISABLE_OPTIONAL_SENSORS + "=" + p.disableOptionalSensors); pw.println(KEY_DISABLE_AOD + "=" + p.disableAod); - pw.println(KEY_DISABLE_SOUNDTRIGGER + "=" + p.disableSoundTrigger); + pw.println(KEY_SOUNDTRIGGER_MODE + "=" + p.soundTriggerMode); pw.println(KEY_ENABLE_QUICK_DOZE + "=" + p.enableQuickDoze); pw.println(KEY_ENABLE_NIGHT_MODE + "=" + p.enableNightMode); diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java index 9bd488d3df7e0..4671b09b5cffb 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java @@ -48,10 +48,12 @@ public class BatterySaverPolicyTest extends AndroidTestCase { private static final int GPS_MODE = 0; // LOCATION_MODE_NO_CHANGE private static final int DEFAULT_GPS_MODE = PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF; + private static final int SOUND_TRIGGER_MODE = 0; // SOUND_TRIGGER_MODE_ALL_ENABLED + private static final int DEFAULT_SOUND_TRIGGER_MODE = + PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY; private static final String BATTERY_SAVER_CONSTANTS = "disable_vibration=true," + "advertise_is_enabled=true," + "disable_animation=false," - + "disable_soundtrigger=true," + "enable_firewall=true," + "enable_datasaver=true," + "enable_brightness_adjustment=false," @@ -59,6 +61,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { + "defer_full_backup=true," + "defer_keyvalue_backup=false," + "location_mode=0," // LOCATION_MODE_NO_CHANGE + + "soundtrigger_mode=0," // SOUND_TRIGGER_MODE_ALL_ENABLE + "enable_night_mode=false," + "enable_quick_doze=true"; private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true"; @@ -125,6 +128,11 @@ public class BatterySaverPolicyTest extends AndroidTestCase { @SmallTest public void testGetBatterySaverPolicy_PolicySound_DefaultValueCorrect() { testServiceDefaultValue_On(ServiceType.SOUND); + + mBatterySaverPolicy.setPolicyLevel(POLICY_LEVEL_FULL); + PowerSaveState stateOn = + mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SOUND); + assertThat(stateOn.soundTriggerMode).isEqualTo(DEFAULT_SOUND_TRIGGER_MODE); } @SmallTest @@ -211,6 +219,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { final PowerSaveState soundState = mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SOUND); assertThat(soundState.batterySaverEnabled).isTrue(); + assertThat(soundState.soundTriggerMode).isEqualTo(SOUND_TRIGGER_MODE); final PowerSaveState networkState = mBatterySaverPolicy.getBatterySaverPolicy( ServiceType.NETWORK_FIREWALL); @@ -408,7 +417,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase { + "," + BatterySaverPolicy.KEY_DISABLE_AOD + "=true" + "," + BatterySaverPolicy.KEY_DISABLE_LAUNCH_BOOST + "=true" + "," + BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS + "=true" - + "," + BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER + "=true" + "," + BatterySaverPolicy.KEY_DISABLE_VIBRATION + "=true" + "," + BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT + "=true" + "," + BatterySaverPolicy.KEY_ENABLE_DATASAVER + "=true" @@ -418,7 +426,9 @@ public class BatterySaverPolicyTest extends AndroidTestCase { + "," + BatterySaverPolicy.KEY_FORCE_ALL_APPS_STANDBY + "=true" + "," + BatterySaverPolicy.KEY_FORCE_BACKGROUND_CHECK + "=true" + "," + BatterySaverPolicy.KEY_LOCATION_MODE - + "=" + PowerManager.LOCATION_MODE_FOREGROUND_ONLY, + + "=" + PowerManager.LOCATION_MODE_FOREGROUND_ONLY + + "," + BatterySaverPolicy.KEY_SOUNDTRIGGER_MODE + + "=" + PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY, "", new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_BATTERY_SAVER) .setFloat(BatterySaverPolicy.KEY_ADJUST_BRIGHTNESS_FACTOR, .5f) @@ -429,7 +439,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase { .setBoolean(BatterySaverPolicy.KEY_DISABLE_AOD, false) .setBoolean(BatterySaverPolicy.KEY_DISABLE_LAUNCH_BOOST, false) .setBoolean(BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS, false) - .setBoolean(BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER, false) .setBoolean(BatterySaverPolicy.KEY_DISABLE_VIBRATION, false) .setBoolean(BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT, false) .setBoolean(BatterySaverPolicy.KEY_ENABLE_DATASAVER, false) @@ -440,6 +449,8 @@ public class BatterySaverPolicyTest extends AndroidTestCase { .setBoolean(BatterySaverPolicy.KEY_FORCE_BACKGROUND_CHECK, false) .setInt(BatterySaverPolicy.KEY_LOCATION_MODE, PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) + .setInt(BatterySaverPolicy.KEY_SOUNDTRIGGER_MODE, + PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED) .build(), null); assertEquals(.1f, policy.adjustBrightnessFactor); @@ -450,7 +461,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase { assertTrue(policy.disableAod); assertTrue(policy.disableLaunchBoost); assertTrue(policy.disableOptionalSensors); - assertTrue(policy.disableSoundTrigger); assertTrue(policy.disableVibration); assertTrue(policy.enableAdjustBrightness); assertTrue(policy.enableDataSaver); @@ -460,6 +470,7 @@ public class BatterySaverPolicyTest extends AndroidTestCase { assertTrue(policy.forceAllAppsStandby); assertTrue(policy.forceBackgroundCheck); assertEquals(PowerManager.LOCATION_MODE_FOREGROUND_ONLY, policy.locationMode); + assertEquals(PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY, policy.soundTriggerMode); } public void testDeviceConfigOverridesDefaults() { @@ -474,7 +485,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase { .setBoolean(BatterySaverPolicy.KEY_DISABLE_AOD, false) .setBoolean(BatterySaverPolicy.KEY_DISABLE_LAUNCH_BOOST, false) .setBoolean(BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS, false) - .setBoolean(BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER, false) .setBoolean(BatterySaverPolicy.KEY_DISABLE_VIBRATION, false) .setBoolean(BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT, false) .setBoolean(BatterySaverPolicy.KEY_ENABLE_DATASAVER, false) @@ -485,6 +495,8 @@ public class BatterySaverPolicyTest extends AndroidTestCase { .setBoolean(BatterySaverPolicy.KEY_FORCE_BACKGROUND_CHECK, false) .setInt(BatterySaverPolicy.KEY_LOCATION_MODE, PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) + .setInt(BatterySaverPolicy.KEY_SOUNDTRIGGER_MODE, + PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED) .build(), null); assertEquals(.5f, policy.adjustBrightnessFactor); @@ -495,7 +507,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase { assertFalse(policy.disableAod); assertFalse(policy.disableLaunchBoost); assertFalse(policy.disableOptionalSensors); - assertFalse(policy.disableSoundTrigger); assertFalse(policy.disableVibration); assertFalse(policy.enableAdjustBrightness); assertFalse(policy.enableDataSaver); @@ -506,6 +517,8 @@ public class BatterySaverPolicyTest extends AndroidTestCase { assertFalse(policy.forceBackgroundCheck); assertEquals(PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF, policy.locationMode); + assertEquals(PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED, + policy.soundTriggerMode); } public void testDeviceConfig_AdaptiveValues() { @@ -521,7 +534,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase { .setBoolean(BatterySaverPolicy.KEY_DISABLE_AOD, false) .setBoolean(BatterySaverPolicy.KEY_DISABLE_LAUNCH_BOOST, false) .setBoolean(BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS, false) - .setBoolean(BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER, false) .setBoolean(BatterySaverPolicy.KEY_DISABLE_VIBRATION, false) .setBoolean(BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT, false) .setBoolean(BatterySaverPolicy.KEY_ENABLE_DATASAVER, false) @@ -532,6 +544,8 @@ public class BatterySaverPolicyTest extends AndroidTestCase { .setBoolean(BatterySaverPolicy.KEY_FORCE_BACKGROUND_CHECK, false) .setInt(BatterySaverPolicy.KEY_LOCATION_MODE, PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) + .setInt(BatterySaverPolicy.KEY_SOUNDTRIGGER_MODE, + PowerManager.SOUND_TRIGGER_MODE_ALL_DISABLED) .setFloat(BatterySaverPolicy.KEY_ADJUST_BRIGHTNESS_FACTOR + adaptiveSuffix, .9f) .setBoolean(BatterySaverPolicy.KEY_ADVERTISE_IS_ENABLED + adaptiveSuffix, @@ -546,8 +560,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase { .setBoolean( BatterySaverPolicy.KEY_DISABLE_OPTIONAL_SENSORS + adaptiveSuffix, true) - .setBoolean(BatterySaverPolicy.KEY_DISABLE_SOUNDTRIGGER + adaptiveSuffix, - true) .setBoolean(BatterySaverPolicy.KEY_DISABLE_VIBRATION + adaptiveSuffix, true) .setBoolean(BatterySaverPolicy.KEY_ENABLE_BRIGHTNESS_ADJUSTMENT + adaptiveSuffix, true) @@ -561,6 +573,8 @@ public class BatterySaverPolicyTest extends AndroidTestCase { true) .setInt(BatterySaverPolicy.KEY_LOCATION_MODE + adaptiveSuffix, PowerManager.LOCATION_MODE_FOREGROUND_ONLY) + .setInt(BatterySaverPolicy.KEY_SOUNDTRIGGER_MODE + adaptiveSuffix, + PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY) .build(), adaptiveSuffix); assertEquals(.9f, policy.adjustBrightnessFactor); assertTrue(policy.advertiseIsEnabled); @@ -570,7 +584,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase { assertTrue(policy.disableAod); assertTrue(policy.disableLaunchBoost); assertTrue(policy.disableOptionalSensors); - assertTrue(policy.disableSoundTrigger); assertTrue(policy.disableVibration); assertTrue(policy.enableAdjustBrightness); assertTrue(policy.enableDataSaver); @@ -580,5 +593,6 @@ public class BatterySaverPolicyTest extends AndroidTestCase { assertTrue(policy.forceAllAppsStandby); assertTrue(policy.forceBackgroundCheck); assertEquals(PowerManager.LOCATION_MODE_FOREGROUND_ONLY, policy.locationMode); + assertEquals(PowerManager.SOUND_TRIGGER_MODE_CRITICAL_ONLY, policy.soundTriggerMode); } } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java index 283fae563ea34..16d83d133fbe6 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 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 modelDatas = new ArrayList(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 + * + *

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 7cec783fb7c05..7071e23a5ebb8 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 bd678fd540634..7a53f1e159a96 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 ec371bf311609..9f203e1090bd3 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);