From c0a3c8c5f8b88a76e118f4c3a0165b0c8df84c82 Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Fri, 4 Dec 2020 08:33:17 -0800 Subject: [PATCH 1/3] add SoundTrigger service modes in battery saver Control over the SoundTrigger service behavior in battery saver mode is expanded to from a boolean to multiple modes. Modes include enabled, disabled, and privileged. Adding the privedged mode allows for the SoundTrigger service to selectively control clients which are deemed esential to the Android system. Bug: 172294448 Test: atest BatterySaverPolicyTest Test: atest CtsBatterySavingTestCases Test: atest PowerManagerTest Test: build and verify backward compatibility with SoundTrigger system service behavior Change-Id: Ib701963b07b205e5902ef265198b390a9850cb88 --- core/api/system-current.txt | 9 ++- .../android/os/BatterySaverPolicyConfig.java | 43 ++++++++++--- core/java/android/os/PowerManager.java | 59 +++++++++++++++++ core/java/android/os/PowerSaveState.java | 10 +++ .../coretests/jni/NativePowerManagerTest.cpp | 22 ++++--- .../src/android/os/PowerManagerTest.java | 26 +++++--- .../batterysaver/BatterySaverPolicy.java | 64 +++++++++++-------- .../batterysaver/BatterySaverPolicyTest.java | 36 +++++++---- 8 files changed, 204 insertions(+), 65 deletions(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index e4cf28ce1921d..2e9aedd812372 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -7870,7 +7870,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 +7880,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 +7897,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 +7907,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 +8268,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 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/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/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); } } From 06c85480acf8a77106d3047f24a2370ac7de06ff Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Fri, 20 Nov 2020 15:42:32 -0800 Subject: [PATCH 2/3] add SOUND_TRIGGER_RUN_IN_BATTERY_SAVER permission New privledged permission added for OEMs to control which SoundTrigger framework interface clients can run in battery saver mode Bug: 172294448 Test: simple build verification Change-Id: If4911d46367e2cd16a2dfff67f7a13753f073f53 --- core/api/system-current.txt | 1 + core/res/AndroidManifest.xml | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 2e9aedd812372..972995bf74e94 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"; 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 @@ + + + From 28cc6364d639016fa9fccf98f2ab4bc005d08b7d Mon Sep 17 00:00:00 2001 From: Nicholas Ambur Date: Fri, 20 Nov 2020 15:50:02 -0800 Subject: [PATCH 3/3] 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 --- core/api/system-current.txt | 2 + .../voice/AlwaysOnHotwordDetector.java | 13 +- .../internal/app/ISoundTriggerSession.aidl | 2 +- .../IVoiceInteractionSoundTriggerSession.aidl | 3 +- .../soundtrigger/SoundTriggerDetector.java | 16 +- .../soundtrigger/SoundTriggerHelper.java | 156 +++++++++++------- .../soundtrigger/SoundTriggerInternal.java | 6 +- .../soundtrigger/SoundTriggerService.java | 15 +- .../VoiceInteractionManagerService.java | 10 +- 9 files changed, 151 insertions(+), 72 deletions(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 972995bf74e94..7833eda405e64 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -5061,6 +5061,7 @@ package android.media.soundtrigger { field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1 field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION = 4; // 0x4 field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 8; // 0x8 + field public static final int RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER = 16; // 0x10 } public abstract static class SoundTriggerDetector.Callback { @@ -10204,6 +10205,7 @@ package android.service.voice { field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1 field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION = 4; // 0x4 field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 8; // 0x8 + field public static final int RECOGNITION_FLAG_RUN_IN_BATTERY_SAVER = 16; // 0x10 field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2 field public static final int RECOGNITION_MODE_VOICE_TRIGGER = 1; // 0x1 field public static final int STATE_ERROR = 3; // 0x3 diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 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/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/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);