Add BatterySaverPolicy for power save mode

The BatterySaverPolicy is designed to consolidate all battery saver
knobs into a central location. Usually it is consistent to
mLowPowerModeEnabled unless it gets different data for specific
service. By adding these knobs, we can effectively tune the battery
saver.

This cl sets up the framework for BatterySaverPolicy and updates
following service to get battery saver data from BatterySaverPolicy

1. GnssLocationProvider
2. VibratorService
3. WindowManagerService
4. BackupManagerService
5. SoundTriggerService
6. NetworkPolicyManagerService

Screen brightness will come in a following cl.

Bug: 34693888
Test: FrameworksServicesTests

Change-Id: I6b040e93391614b44d136a485faa4a332c396e51
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 1d464c0..b715780 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -2,22 +2,23 @@
 **
 ** Copyright 2007, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 package android.os;
 
 import android.os.WorkSource;
+import android.os.PowerSaveState;
 
 /** @hide */
 
@@ -45,6 +46,7 @@
     void nap(long time);
     boolean isInteractive();
     boolean isPowerSaveMode();
+    PowerSaveState getPowerSaveState(int serviceType);
     boolean setPowerSaveMode(boolean mode);
     boolean isDeviceIdleMode();
     boolean isLightDeviceIdleMode();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 31b3bc9..a713eef 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -971,6 +971,24 @@
     }
 
     /**
+     * Get data about the battery saver mode for a specific service
+     * @param serviceType unique key for the service, one of
+     *             {@link com.android.server.power.BatterySaverPolicy.ServiceType}
+     * @return Battery saver state data.
+     *
+     * @hide
+     * @see com.android.server.power.BatterySaverPolicy
+     * @see PowerSaveState
+     */
+    public PowerSaveState getPowerSaveState(int serviceType) {
+        try {
+            return mService.getPowerSaveState(serviceType);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * 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
      * it decides to go into a lower power-use state.  This may involve things like turning
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index d0db255..44addfc 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -131,12 +131,13 @@
     public abstract void setDozeOverrideFromDreamManager(
             int screenState, int screenBrightness);
 
-    public abstract boolean getLowPowerModeEnabled();
+    public abstract PowerSaveState getLowPowerState(int serviceType);
 
     public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
 
     public interface LowPowerModeListener {
-        public void onLowPowerModeChanged(boolean enabled);
+        int getServiceType();
+        void onLowPowerModeChanged(PowerSaveState state);
     }
 
     public abstract boolean setDeviceIdleMode(boolean enabled);
diff --git a/core/java/android/os/PowerSaveState.aidl b/core/java/android/os/PowerSaveState.aidl
new file mode 100644
index 0000000..e3f572d
--- /dev/null
+++ b/core/java/android/os/PowerSaveState.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+parcelable PowerSaveState;
\ No newline at end of file
diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java
new file mode 100644
index 0000000..9269e76
--- /dev/null
+++ b/core/java/android/os/PowerSaveState.java
@@ -0,0 +1,95 @@
+/* Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.os;
+
+/**
+ * Data class for battery saver state. It contains the data
+ * <p>
+ * 1. Whether battery saver mode is enabled
+ * 2. Specific parameters to use in battery saver mode(i.e. screen brightness, gps mode)
+ *
+ * @hide
+ */
+public class PowerSaveState implements Parcelable {
+    public final boolean batterySaverEnabled;
+    public final int gpsMode;
+    public final float brightnessFactor;
+
+    public PowerSaveState(Builder builder) {
+        batterySaverEnabled = builder.mBatterySaverEnabled;
+        gpsMode = builder.mGpsMode;
+        brightnessFactor = builder.mBrightnessFactor;
+    }
+
+    public PowerSaveState(Parcel in) {
+        batterySaverEnabled = in.readByte() != 0;
+        gpsMode = in.readInt();
+        brightnessFactor = in.readFloat();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeByte((byte) (batterySaverEnabled ? 1 : 0));
+        dest.writeInt(gpsMode);
+        dest.writeFloat(brightnessFactor);
+    }
+
+    public static final class Builder {
+        private boolean mBatterySaverEnabled = false;
+        private int mGpsMode = 0;
+        private float mBrightnessFactor = 0.5f;
+
+        public Builder() {}
+
+        public Builder setBatterySaverEnabled(boolean enabled) {
+            mBatterySaverEnabled = enabled;
+            return this;
+        }
+
+        public Builder setGpsMode(int mode) {
+            mGpsMode = mode;
+            return this;
+        }
+
+        public Builder setBrightnessFactor(float factor) {
+            mBrightnessFactor = factor;
+            return this;
+        }
+
+        public PowerSaveState build() {
+            return new PowerSaveState(this);
+        }
+    }
+
+    public static final Parcelable.Creator<PowerSaveState>
+            CREATOR = new Parcelable.Creator<PowerSaveState>() {
+
+        @Override
+        public PowerSaveState createFromParcel(Parcel source) {
+            return new PowerSaveState(source);
+        }
+
+        @Override
+        public PowerSaveState[] newArray(int size) {
+            return new PowerSaveState[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 73d61c3..4e78635 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8956,6 +8956,30 @@
         public static final String DEVICE_IDLE_CONSTANTS_WATCH = "device_idle_constants_watch";
 
         /**
+         * Battery Saver specific settings
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "vibration_disabled=true,adjust_brightness_factor=0.5"
+         *
+         * The following keys are supported:
+         *
+         * <pre>
+         * vibration_disabled                (boolean)
+         * animation_disabled                (boolean)
+         * soundtrigger_disabled             (boolean)
+         * fullbackup_deferred               (boolean)
+         * keyvaluebackup_deferred           (boolean)
+         * firewall_disabled                 (boolean)
+         * gps_mode                          (int)
+         * adjust_brightness_disabled        (boolean)
+         * adjust_brightness_factor          (float)
+         * </pre>
+         * @hide
+         * @see com.android.server.power.BatterySaverPolicy
+         */
+        public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
+
+        /**
          * App standby (app idle) specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          *
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 9a64507..696d498 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -158,6 +158,7 @@
                     Settings.Global.DEVICE_DEMO_MODE,
                     Settings.Global.DEVICE_IDLE_CONSTANTS,
                     Settings.Global.DEVICE_IDLE_CONSTANTS_WATCH,
+                    Settings.Global.BATTERY_SAVER_CONSTANTS,
                     Settings.Global.DEVICE_NAME,
                     Settings.Global.DEVICE_PROVISIONED,
                     Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED,
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index c26032ce..8f2b428 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -80,6 +80,7 @@
 import android.content.pm.Signature;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.PowerSaveState;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -122,6 +123,7 @@
 import com.android.server.SystemService;
 import com.android.server.backup.PackageManagerBackupAgent.Metadata;
 
+import com.android.server.power.BatterySaverPolicy.ServiceType;
 import libcore.io.IoUtils;
 
 import java.io.BufferedInputStream;
@@ -5440,7 +5442,9 @@
 
         // Don't run the backup if we're in battery saver mode, but reschedule
         // to try again in the not-so-distant future.
-        if (mPowerManager.isPowerSaveMode()) {
+        final PowerSaveState result =
+                mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP);
+        if (result.batterySaverEnabled) {
             if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode");
             FullBackupJob.schedule(mContext, KeyValueBackupJob.BATCH_INTERVAL);
             return false;
@@ -9889,7 +9893,9 @@
     public void backupNow() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
 
-        if (mPowerManager.isPowerSaveMode()) {
+        final PowerSaveState result =
+                mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP);
+        if (result.batterySaverEnabled) {
             if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode");
             KeyValueBackupJob.schedule(mContext);   // try again in several hours
         } else {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 8888325..5fe6952 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -25,6 +25,7 @@
 import android.database.ContentObserver;
 import android.hardware.input.InputManager;
 import android.media.AudioManager;
+import android.os.PowerSaveState;
 import android.os.BatteryStats;
 import android.os.Handler;
 import android.os.IVibratorService;
@@ -50,6 +51,7 @@
 
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
+import com.android.server.power.BatterySaverPolicy.ServiceType;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -233,10 +235,15 @@
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         mPowerManagerInternal.registerLowPowerModeObserver(
                 new PowerManagerInternal.LowPowerModeListener() {
-            @Override
-            public void onLowPowerModeChanged(boolean enabled) {
-                updateInputDeviceVibrators();
-            }
+                    @Override
+                    public int getServiceType() {
+                        return ServiceType.VIBRATION;
+                    }
+
+                    @Override
+                    public void onLowPowerModeChanged(PowerSaveState result) {
+                        updateInputDeviceVibrators();
+                    }
         });
 
         mContext.getContentResolver().registerContentObserver(
@@ -553,7 +560,8 @@
                 } catch (SettingNotFoundException snfe) {
                 }
 
-                mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled();
+                mLowPowerMode = mPowerManagerInternal
+                        .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
 
                 if (mVibrateInputDevicesSetting) {
                     if (!mInputDeviceListenerRegistered) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3571302..1712d48 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.WifiActivityEnergyInfo;
+import android.os.PowerSaveState;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Handler;
@@ -60,6 +61,7 @@
 import com.android.internal.os.PowerProfile;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
+import com.android.server.power.BatterySaverPolicy.ServiceType;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -232,7 +234,9 @@
     public void initPowerManagement() {
         final PowerManagerInternal powerMgr = LocalServices.getService(PowerManagerInternal.class);
         powerMgr.registerLowPowerModeObserver(this);
-        mStats.notePowerSaveMode(powerMgr.getLowPowerModeEnabled());
+        mStats.notePowerSaveMode(
+                powerMgr.getLowPowerState(ServiceType.BATTERY_STATS)
+                        .batterySaverEnabled);
         (new WakeupReasonThread()).start();
     }
 
@@ -258,9 +262,14 @@
     }
 
     @Override
-    public void onLowPowerModeChanged(boolean enabled) {
+    public int getServiceType() {
+        return ServiceType.BATTERY_STATS;
+    }
+
+    @Override
+    public void onLowPowerModeChanged(PowerSaveState result) {
         synchronized (mStats) {
-            mStats.notePowerSaveMode(enabled);
+            mStats.notePowerSaveMode(result.batterySaverEnabled);
         }
     }
 
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index fdaba0b..3a1ddd7 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -16,13 +16,6 @@
 
 package com.android.server.location;
 
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.app.IBatteryStats;
-import com.android.internal.location.GpsNetInitiatedHandler;
-import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
-import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
-
 import android.app.AlarmManager;
 import android.app.AppOpsManager;
 import android.app.PendingIntent;
@@ -55,6 +48,7 @@
 import android.net.NetworkRequest;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.PowerSaveState;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Bundle;
@@ -81,6 +75,17 @@
 import android.util.Log;
 import android.util.NtpTrustedTime;
 
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.location.GpsNetInitiatedHandler;
+import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.server.power.BatterySaverPolicy;
+import com.android.server.power.BatterySaverPolicy.ServiceType;
+
+import libcore.io.IoUtils;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -96,7 +101,6 @@
 import java.util.Properties;
 import java.util.Map;
 import java.util.HashMap;
-import libcore.io.IoUtils;
 
 /**
  * A GNSS implementation of LocationProvider used by LocationManager.
@@ -243,14 +247,6 @@
     private static final int TCP_MIN_PORT = 0;
     private static final int TCP_MAX_PORT = 0xffff;
 
-    // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
-    private static final int BATTERY_SAVER_MODE_NO_CHANGE = 0;
-    // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
-    // is enabled and the screen is off.
-    private static final int BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
-    // Secure setting for GPS behavior when battery saver mode is on.
-    private static final String BATTERY_SAVER_GPS_MODE = "batterySaverGpsMode";
-
     /** simpler wrapper for ProviderRequest + Worksource */
     private static class GpsRequest {
         public ProviderRequest request;
@@ -548,11 +544,12 @@
     private void updateLowPowerMode() {
         // Disable GPS if we are in device idle mode.
         boolean disableGps = mPowerManager.isDeviceIdleMode();
-        switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE,
-                BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) {
-            case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF:
+        final PowerSaveState result =
+                mPowerManager.getPowerSaveState(ServiceType.GPS);
+        switch (result.gpsMode) {
+            case BatterySaverPolicy.GPS_MODE_DISABLED_WHEN_SCREEN_OFF:
                 // If we are in battery saver mode and the screen is off, disable GPS.
-                disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive();
+                disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive();
                 break;
         }
         if (disableGps != mDisableGps) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 5078998..4e9d838 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -131,6 +131,7 @@
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.os.PowerSaveState;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
@@ -180,6 +181,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 
+import com.android.server.power.BatterySaverPolicy.ServiceType;
 import libcore.io.IoUtils;
 
 import com.google.android.collect.Lists;
@@ -590,18 +592,26 @@
                     mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
                     mPowerManagerInternal.registerLowPowerModeObserver(
                             new PowerManagerInternal.LowPowerModeListener() {
-                        @Override
-                        public void onLowPowerModeChanged(boolean enabled) {
-                            if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
-                            synchronized (mUidRulesFirstLock) {
-                                if (mRestrictPower != enabled) {
-                                    mRestrictPower = enabled;
-                                    updateRulesForRestrictPowerUL();
+                                @Override
+                                public int getServiceType() {
+                                    return ServiceType.NETWORK_FIREWALL;
                                 }
-                            }
-                        }
+
+                                @Override
+                                public void onLowPowerModeChanged(PowerSaveState result) {
+                                    final boolean enabled = result.batterySaverEnabled;
+                                    if (LOGD) Slog.d(TAG,
+                                            "onLowPowerModeChanged(" + enabled + ")");
+                                    synchronized (mUidRulesFirstLock) {
+                                        if (mRestrictPower != enabled) {
+                                            mRestrictPower = enabled;
+                                            updateRulesForRestrictPowerUL();
+                                        }
+                                    }
+                                }
                     });
-                    mRestrictPower = mPowerManagerInternal.getLowPowerModeEnabled();
+                    mRestrictPower = mPowerManagerInternal.getLowPowerState(
+                            ServiceType.NETWORK_FIREWALL).batterySaverEnabled;
 
                     mSystemReady = true;
 
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
new file mode 100644
index 0000000..8d20531
--- /dev/null
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.power;
+
+import android.annotation.IntDef;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+import android.os.PowerSaveState;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class to decide whether to turn on battery saver mode for specific service
+ */
+public class BatterySaverPolicy extends ContentObserver {
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ServiceType.GPS,
+            ServiceType.VIBRATION,
+            ServiceType.ANIMATION,
+            ServiceType.FULL_BACKUP,
+            ServiceType.KEYVALUE_BACKUP,
+            ServiceType.NETWORK_FIREWALL,
+            ServiceType.SCREEN_BRIGHTNESS,
+            ServiceType.SOUND,
+            ServiceType.BATTERY_STATS})
+    public @interface ServiceType {
+        int NULL = 0;
+        int GPS = 1;
+        int VIBRATION = 2;
+        int ANIMATION = 3;
+        int FULL_BACKUP = 4;
+        int KEYVALUE_BACKUP = 5;
+        int NETWORK_FIREWALL = 6;
+        int SCREEN_BRIGHTNESS = 7;
+        int SOUND = 8;
+        int BATTERY_STATS = 9;
+    }
+
+    private static final String TAG = "BatterySaverPolicy";
+
+    // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
+    public static final int GPS_MODE_NO_CHANGE = 0;
+    // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
+    // is enabled and the screen is off.
+    public static final int GPS_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
+    // Secure setting for GPS behavior when battery saver mode is on.
+    public static final String SECURE_KEY_GPS_MODE = "batterySaverGpsMode";
+
+    private static final String KEY_GPS_MODE = "gps_mode";
+    private static final String KEY_VIBRATION_DISABLED = "vibration_disabled";
+    private static final String KEY_ANIMATION_DISABLED = "animation_disabled";
+    private static final String KEY_SOUNDTRIGGER_DISABLED = "soundtrigger_disabled";
+    private static final String KEY_FIREWALL_DISABLED = "firewall_disabled";
+    private static final String KEY_ADJUST_BRIGHTNESS_DISABLED = "adjust_brightness_disabled";
+    private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
+    private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
+    private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
+
+    private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+    /**
+     * {@code true} if vibration is disabled in battery saver mode.
+     *
+     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+     * @see #KEY_VIBRATION_DISABLED
+     */
+    private boolean mVibrationDisabled;
+
+    /**
+     * {@code true} if animation is disabled in battery saver mode.
+     *
+     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+     * @see #KEY_ANIMATION_DISABLED
+     */
+    private boolean mAnimationDisabled;
+
+    /**
+     * {@code true} if sound trigger is disabled in battery saver mode
+     * in battery saver mode.
+     *
+     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+     * @see #KEY_SOUNDTRIGGER_DISABLED
+     */
+    private boolean mSoundTriggerDisabled;
+
+    /**
+     * {@code true} if full backup is deferred in battery saver mode.
+     *
+     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+     * @see #KEY_FULLBACKUP_DEFERRED
+     */
+    private boolean mFullBackupDeferred;
+
+    /**
+     * {@code true} if key value backup is deferred in battery saver mode.
+     *
+     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+     * @see #KEY_KEYVALUE_DEFERRED
+     */
+    private boolean mKeyValueBackupDeferred;
+
+    /**
+     * {@code true} if network policy firewall is disabled in battery saver mode.
+     *
+     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+     * @see #KEY_FIREWALL_DISABLED
+     */
+    private boolean mFireWallDisabled;
+
+    /**
+     * {@code true} if adjust brightness is disabled in battery saver mode.
+     *
+     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+     * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
+     */
+    private boolean mAdjustBrightnessDisabled;
+
+    /**
+     * This is the flag to decide the gps mode in battery saver mode.
+     *
+     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+     * @see #KEY_GPS_MODE
+     */
+    private int mGpsMode;
+
+    /**
+     * This is the flag to decide the how much to adjust the screen brightness. This is
+     * the float value from 0 to 1 where 1 means don't change brightness.
+     *
+     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
+     * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
+     */
+    private float mAdjustBrightnessFactor;
+
+    private ContentResolver mContentResolver;
+
+    public BatterySaverPolicy(Handler handler) {
+        super(handler);
+    }
+
+    public void start(ContentResolver contentResolver) {
+        mContentResolver = contentResolver;
+
+        mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+                Settings.Global.BATTERY_SAVER_CONSTANTS), false, this);
+        onChange(true, null);
+    }
+
+    @Override
+    public void onChange(boolean selfChange, Uri uri) {
+        final String value = Settings.Global.getString(mContentResolver,
+                Settings.Global.BATTERY_SAVER_CONSTANTS);
+        updateConstants(value);
+    }
+
+    @VisibleForTesting
+    void updateConstants(final String value) {
+        synchronized (BatterySaverPolicy.this) {
+            try {
+                mParser.setString(value);
+            } catch (IllegalArgumentException e) {
+                Slog.e(TAG, "Bad battery saver constants");
+            }
+
+            mVibrationDisabled = mParser.getBoolean(KEY_VIBRATION_DISABLED, true);
+            mAnimationDisabled = mParser.getBoolean(KEY_ANIMATION_DISABLED, true);
+            mSoundTriggerDisabled = mParser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true);
+            mFullBackupDeferred = mParser.getBoolean(KEY_FULLBACKUP_DEFERRED, true);
+            mKeyValueBackupDeferred = mParser.getBoolean(KEY_KEYVALUE_DEFERRED, true);
+            mFireWallDisabled = mParser.getBoolean(KEY_FIREWALL_DISABLED, false);
+            mAdjustBrightnessDisabled = mParser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, false);
+            mAdjustBrightnessFactor = mParser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
+
+            // Get default value from Settings.Secure
+            final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
+                    GPS_MODE_DISABLED_WHEN_SCREEN_OFF);
+            mGpsMode = mParser.getInt(KEY_GPS_MODE, defaultGpsMode);
+        }
+    }
+
+    /**
+     * Get the {@link PowerSaveState} based on {@paramref type} and {@paramref realMode}.
+     * The result will have {@link PowerSaveState#batterySaverEnabled} and some other
+     * parameters when necessary.
+     *
+     * @param type     type of the service, one of {@link ServiceType}
+     * @param realMode whether the battery saver is on by default
+     * @return State data that contains battery saver data
+     */
+    public PowerSaveState getBatterySaverPolicy(@ServiceType int type, boolean realMode) {
+        synchronized (BatterySaverPolicy.this) {
+            final PowerSaveState.Builder builder = new PowerSaveState.Builder();
+            if (!realMode) {
+                return builder.setBatterySaverEnabled(realMode)
+                        .build();
+            }
+            switch (type) {
+                case ServiceType.GPS:
+                    return builder.setBatterySaverEnabled(realMode)
+                            .setGpsMode(mGpsMode)
+                            .build();
+                case ServiceType.ANIMATION:
+                    return builder.setBatterySaverEnabled(mAnimationDisabled)
+                            .build();
+                case ServiceType.FULL_BACKUP:
+                    return builder.setBatterySaverEnabled(mFullBackupDeferred)
+                            .build();
+                case ServiceType.KEYVALUE_BACKUP:
+                    return builder.setBatterySaverEnabled(mKeyValueBackupDeferred)
+                            .build();
+                case ServiceType.NETWORK_FIREWALL:
+                    return builder.setBatterySaverEnabled(!mFireWallDisabled)
+                            .build();
+                case ServiceType.SCREEN_BRIGHTNESS:
+                    return builder.setBatterySaverEnabled(!mAdjustBrightnessDisabled)
+                            .setBrightnessFactor(mAdjustBrightnessFactor)
+                            .build();
+                case ServiceType.SOUND:
+                    return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
+                            .build();
+                case ServiceType.VIBRATION:
+                    return builder.setBatterySaverEnabled(mVibrationDisabled)
+                            .build();
+                default:
+                    return builder.setBatterySaverEnabled(realMode)
+                            .build();
+            }
+        }
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println();
+        pw.println("Battery saver policy");
+        pw.println("  Settings " + Settings.Global.BATTERY_SAVER_CONSTANTS);
+        pw.println("  value: " + Settings.Global.getString(mContentResolver,
+                Settings.Global.BATTERY_SAVER_CONSTANTS));
+
+        pw.println();
+        pw.println("  " + KEY_VIBRATION_DISABLED + "=" + mVibrationDisabled);
+        pw.println("  " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled);
+        pw.println("  " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
+        pw.println("  " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
+        pw.println("  " + KEY_FIREWALL_DISABLED + "=" + mFireWallDisabled);
+        pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
+        pw.println("  " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
+        pw.println("  " + KEY_GPS_MODE + "=" + mGpsMode);
+
+    }
+}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index d3931fb..cd63527 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -35,6 +35,7 @@
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
+import android.os.PowerSaveState;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -80,7 +81,7 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
-
+import com.android.server.power.BatterySaverPolicy.ServiceType;
 import libcore.util.Objects;
 
 import java.io.FileDescriptor;
@@ -192,6 +193,7 @@
     private final Context mContext;
     private final ServiceThread mHandlerThread;
     private final PowerManagerHandler mHandler;
+    private final BatterySaverPolicy mBatterySaverPolicy;
 
     private LightsManager mLightsManager;
     private BatteryManagerInternal mBatteryManagerInternal;
@@ -605,6 +607,7 @@
         mHandlerThread.start();
         mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
         mConstants = new Constants(mHandler);
+        mBatterySaverPolicy = new BatterySaverPolicy(mHandler);
 
         synchronized (mLock) {
             mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
@@ -704,6 +707,7 @@
 
         final ContentResolver resolver = mContext.getContentResolver();
         mConstants.start(resolver);
+        mBatterySaverPolicy.start(resolver);
 
         // Register for settings changes.
         resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -939,8 +943,12 @@
                         listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(
                                 mLowPowerModeListeners);
                     }
-                    for (int i=0; i<listeners.size(); i++) {
-                        listeners.get(i).onLowPowerModeChanged(lowPowerModeEnabled);
+                    for (int i = 0; i < listeners.size(); i++) {
+                        final PowerManagerInternal.LowPowerModeListener listener = listeners.get(i);
+                        final PowerSaveState result =
+                                mBatterySaverPolicy.getBatterySaverPolicy(
+                                        listener.getServiceType(), lowPowerModeEnabled);
+                        listener.onLowPowerModeChanged(result);
                     }
                     intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -3245,6 +3253,8 @@
             pw.println();
             pw.println("Display Power: " + mDisplayPowerCallbacks);
 
+            mBatterySaverPolicy.dump(pw);
+
             wcd = mWirelessChargerDetector;
         }
 
@@ -4201,6 +4211,19 @@
             }
         }
 
+        // Binder call
+        public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    return mBatterySaverPolicy.getBatterySaverPolicy(
+                            serviceType, isLowPowerModeInternal());
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
         @Override // Binder call
         public boolean setPowerSaveMode(boolean mode) {
             mContext.enforceCallingOrSelfPermission(
@@ -4519,9 +4542,9 @@
         }
 
         @Override
-        public boolean getLowPowerModeEnabled() {
+        public PowerSaveState getLowPowerState(@ServiceType int serviceType) {
             synchronized (mLock) {
-                return mLowPowerModeEnabled;
+                return mBatterySaverPolicy.getBatterySaverPolicy(serviceType, mLowPowerModeEnabled);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index eb3a2d1..4a7b8d4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -129,6 +129,7 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputManager;
 import android.net.Uri;
+import android.os.PowerSaveState;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -219,6 +220,7 @@
 import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.input.InputManagerService;
+import com.android.server.power.BatterySaverPolicy.ServiceType;
 import com.android.server.power.ShutdownThread;
 
 import java.io.BufferedWriter;
@@ -1009,15 +1011,26 @@
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
 
         if (mPowerManagerInternal != null) {
-            mPowerManagerInternal.registerLowPowerModeObserver((enabled) -> {
-                synchronized (mWindowMap) {
-                    if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {
-                        mAnimationsDisabled = enabled;
-                        dispatchNewAnimatorScaleLocked(null);
+            mPowerManagerInternal.registerLowPowerModeObserver(
+                    new PowerManagerInternal.LowPowerModeListener() {
+                @Override
+                public int getServiceType() {
+                    return ServiceType.ANIMATION;
+                }
+
+                @Override
+                public void onLowPowerModeChanged(PowerSaveState result) {
+                    synchronized (mWindowMap) {
+                        final boolean enabled = result.batterySaverEnabled;
+                        if (mAnimationsDisabled != enabled && !mAllowAnimationsInLowPowerMode) {
+                            mAnimationsDisabled = enabled;
+                            dispatchNewAnimatorScaleLocked(null);
+                        }
                     }
                 }
             });
-            mAnimationsDisabled = mPowerManagerInternal.getLowPowerModeEnabled();
+            mAnimationsDisabled = mPowerManagerInternal
+                    .getLowPowerState(ServiceType.ANIMATION).batterySaverEnabled;
         }
         mScreenFrozenLock = mPowerManager.newWakeLock(
                 PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
new file mode 100644
index 0000000..7282b3e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.power;
+
+import android.os.PowerSaveState;
+import android.os.Handler;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.server.power.BatterySaverPolicy.ServiceType;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static com.google.common.truth.Truth.assertThat;
+
+/**
+ * Tests for {@link com.android.server.power.BatterySaverPolicy}
+ */
+public class BatterySaverPolicyTest extends AndroidTestCase {
+    private static final boolean BATTERY_SAVER_ON = true;
+    private static final boolean BATTERY_SAVER_OFF = false;
+    private static final float BRIGHTNESS_FACTOR = 0.7f;
+    private static final float DEFAULT_BRIGHTNESS_FACTOR = 0.5f;
+    private static final float PRECISION = 0.001f;
+    private static final int GPS_MODE = 0;
+    private static final int DEFAULT_GPS_MODE = 1;
+    private static final String BATTERY_SAVER_CONSTANTS = "vibration_disabled=true,"
+            + "animation_disabled=false,"
+            + "soundtrigger_disabled=true,"
+            + "firewall_disabled=false,"
+            + "adjust_brightness_disabled=true,"
+            + "adjust_brightness_factor=0.7,"
+            + "fullbackup_deferred=true,"
+            + "keyvaluebackup_deferred=false,"
+            + "gps_mode=0";
+    private static final String BATTERY_SAVER_INCORRECT_CONSTANTS = "vi*,!=,,true";
+
+    @Mock
+    Handler mHandler;
+    private BatterySaverPolicy mBatterySaverPolicy;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        MockitoAnnotations.initMocks(this);
+        mBatterySaverPolicy = new BatterySaverPolicy(mHandler);
+        mBatterySaverPolicy.start(getContext().getContentResolver());
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyNull_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.NULL);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyVibration_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.VIBRATION);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicySound_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.SOUND);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyFullBackup_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.FULL_BACKUP);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyKeyValueBackup_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.KEYVALUE_BACKUP);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyAnimation_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.ANIMATION);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyBatteryStats_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.BATTERY_STATS);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyNetworkFirewall_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.NETWORK_FIREWALL);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyScreenBrightness_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.SCREEN_BRIGHTNESS);
+
+        PowerSaveState stateOn =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS, true);
+        assertThat(stateOn.brightnessFactor).isWithin(PRECISION).of(DEFAULT_BRIGHTNESS_FACTOR);
+    }
+
+    @SmallTest
+    public void testGetBatterySaverPolicy_PolicyGps_DefaultValueCorrect() {
+        testServiceDefaultValue(ServiceType.GPS);
+
+        PowerSaveState stateOn =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, true);
+        assertThat(stateOn.gpsMode).isEqualTo(DEFAULT_GPS_MODE);
+    }
+
+    @SmallTest
+    public void testUpdateConstants_getCorrectData() {
+        mBatterySaverPolicy.updateConstants(BATTERY_SAVER_CONSTANTS);
+
+        final PowerSaveState vibrationState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.VIBRATION, BATTERY_SAVER_ON);
+        assertThat(vibrationState.batterySaverEnabled).isTrue();
+
+        final PowerSaveState animationState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.ANIMATION, BATTERY_SAVER_ON);
+        assertThat(animationState.batterySaverEnabled).isFalse();
+
+        final PowerSaveState soundState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SOUND, BATTERY_SAVER_ON);
+        assertThat(soundState.batterySaverEnabled).isTrue();
+
+        final PowerSaveState networkState = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.NETWORK_FIREWALL, BATTERY_SAVER_ON);
+        assertThat(networkState.batterySaverEnabled).isTrue();
+
+        final PowerSaveState screenState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS, BATTERY_SAVER_ON);
+        assertThat(screenState.batterySaverEnabled).isFalse();
+        assertThat(screenState.brightnessFactor).isWithin(PRECISION).of(BRIGHTNESS_FACTOR);
+
+        final PowerSaveState fullBackupState = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.FULL_BACKUP, BATTERY_SAVER_ON);
+        assertThat(fullBackupState.batterySaverEnabled).isTrue();
+
+        final PowerSaveState keyValueBackupState = mBatterySaverPolicy.getBatterySaverPolicy(
+                ServiceType.KEYVALUE_BACKUP, BATTERY_SAVER_ON);
+        assertThat(keyValueBackupState.batterySaverEnabled).isFalse();
+
+        final PowerSaveState gpsState =
+                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.GPS, BATTERY_SAVER_ON);
+        assertThat(gpsState.batterySaverEnabled).isTrue();
+        assertThat(gpsState.gpsMode).isEqualTo(GPS_MODE);
+    }
+
+    @SmallTest
+    public void testUpdateConstants_IncorrectData_NotCrash() {
+        //Should not crash
+        mBatterySaverPolicy.updateConstants(BATTERY_SAVER_INCORRECT_CONSTANTS);
+        mBatterySaverPolicy.updateConstants(null);
+    }
+
+    private void testServiceDefaultValue(@ServiceType int type) {
+        mBatterySaverPolicy.updateConstants("");
+        final PowerSaveState batterySaverStateOn =
+                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
+        assertThat(batterySaverStateOn.batterySaverEnabled).isTrue();
+
+        final PowerSaveState batterySaverStateOff =
+                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_OFF);
+        assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index dd45d9b..c8b73f1 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -17,9 +17,13 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doAnswer;
+
+import android.os.PowerSaveState;
 import org.mockito.invocation.InvocationOnMock;
 
 import android.annotation.Nullable;
@@ -67,6 +71,10 @@
             if (LocalServices.getService(PowerManagerInternal.class) == null) {
                 LocalServices.addService(PowerManagerInternal.class,
                         mock(PowerManagerInternal.class));
+                final PowerManagerInternal pm =
+                        LocalServices.getService(PowerManagerInternal.class);
+                PowerSaveState state = new PowerSaveState.Builder().build();
+                doReturn(state).when(pm).getLowPowerState(anyInt());
             }
             if (LocalServices.getService(ActivityManagerInternal.class) == null) {
                 LocalServices.addService(ActivityManagerInternal.class,
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index e89585c..ca37631 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -16,8 +16,6 @@
 
 package com.android.server.soundtrigger;
 
-import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR;
-
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -42,6 +40,7 @@
 import android.telephony.TelephonyManager;
 import android.util.Slog;
 import com.android.internal.logging.MetricsLogger;
+import com.android.server.power.BatterySaverPolicy.ServiceType;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -841,7 +840,8 @@
             if (!PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
                 return;
             }
-            boolean active = mPowerManager.isPowerSaveMode();
+            boolean active = mPowerManager.getPowerSaveState(ServiceType.SOUND)
+                    .batterySaverEnabled;
             if (DBG) Slog.d(TAG, "onPowerSaveModeChanged: " + active);
             synchronized (mLock) {
                 onPowerSaveModeChangedLocked(active);
@@ -874,7 +874,8 @@
             mContext.registerReceiver(mPowerSaveModeListener,
                     new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED));
         }
-        mIsPowerSaveMode = mPowerManager.isPowerSaveMode();
+        mIsPowerSaveMode = mPowerManager.getPowerSaveState(ServiceType.SOUND)
+                .batterySaverEnabled;
     }
 
     // Sends an error callback to all models with a valid registered callback.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 9f73d79..339019d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -18,6 +18,7 @@
 
 import android.os.IBinder;
 import android.os.IPowerManager;
+import android.os.PowerSaveState;
 import android.os.RemoteException;
 import android.os.WorkSource;
 
@@ -42,6 +43,10 @@
         return false;
     }
 
+    public PowerSaveState getPowerSaveState(int serviceType) {
+        return null;
+    }
+
     @Override
     public IBinder asBinder() {
         // pass for now.