1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settingslib.fuelgauge;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.PowerManager;
23 import android.provider.Settings.Global;
24 import android.provider.Settings.Secure;
25 import android.util.KeyValueListParser;
26 import android.util.Log;
27 import android.util.Slog;
28 
29 /**
30  * Utilities related to battery saver.
31  */
32 public class BatterySaverUtils {
33     private static final String TAG = "BatterySaverUtils";
34 
BatterySaverUtils()35     private BatterySaverUtils() {
36     }
37 
38     private static final boolean DEBUG = false;
39 
40     private static final String SYSUI_PACKAGE = "com.android.systemui";
41 
42     /** Broadcast action for SystemUI to show the battery saver confirmation dialog. */
43     public static final String ACTION_SHOW_START_SAVER_CONFIRMATION = "PNW.startSaverConfirmation";
44 
45     /**
46      * Broadcast action for SystemUI to show the notification that suggests turning on
47      * automatic battery saver.
48      */
49     public static final String ACTION_SHOW_AUTO_SAVER_SUGGESTION
50             = "PNW.autoSaverSuggestion";
51 
52     private static class Parameters {
53         private final Context mContext;
54 
55         /**
56          * We show the auto battery saver suggestion notification when the user manually enables
57          * battery saver for the START_NTH time through the END_NTH time.
58          * (We won't show it for END_NTH + 1 time and after.)
59          */
60         private static final int AUTO_SAVER_SUGGESTION_START_NTH = 4;
61         private static final int AUTO_SAVER_SUGGESTION_END_NTH = 8;
62 
63         public final int startNth;
64         public final int endNth;
65 
Parameters(Context context)66         public Parameters(Context context) {
67             mContext = context;
68 
69             final String newValue = Global.getString(mContext.getContentResolver(),
70                     Global.LOW_POWER_MODE_SUGGESTION_PARAMS);
71             final KeyValueListParser parser = new KeyValueListParser(',');
72             try {
73                 parser.setString(newValue);
74             } catch (IllegalArgumentException e) {
75                 Slog.wtf(TAG, "Bad constants: " + newValue);
76             }
77             startNth = parser.getInt("start_nth", AUTO_SAVER_SUGGESTION_START_NTH);
78             endNth = parser.getInt("end_nth", AUTO_SAVER_SUGGESTION_END_NTH);
79         }
80     }
81 
82     /**
83      * Enable / disable battery saver by user request.
84      * - If it's the first time and needFirstTimeWarning, show the first time dialog.
85      * - If it's 4th time through 8th time, show the schedule suggestion notification.
86      *
87      * @param enable true to disable battery saver.
88      *
89      * @return true if the request succeeded.
90      */
setPowerSaveMode(Context context, boolean enable, boolean needFirstTimeWarning)91     public static synchronized boolean setPowerSaveMode(Context context,
92             boolean enable, boolean needFirstTimeWarning) {
93         if (DEBUG) {
94             Log.d(TAG, "Battery saver turning " + (enable ? "ON" : "OFF"));
95         }
96         final ContentResolver cr = context.getContentResolver();
97 
98         if (enable && needFirstTimeWarning && maybeShowBatterySaverConfirmation(context)) {
99             return false;
100         }
101         if (enable && !needFirstTimeWarning) {
102             setBatterySaverConfirmationAcknowledged(context);
103         }
104 
105         if (context.getSystemService(PowerManager.class).setPowerSaveMode(enable)) {
106             if (enable) {
107                 final int count =
108                         Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1;
109                 Secure.putInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, count);
110 
111                 final Parameters parameters = new Parameters(context);
112 
113                 if ((count >= parameters.startNth)
114                         && (count <= parameters.endNth)
115                         && Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0
116                         && Secure.getInt(cr,
117                         Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) {
118                     showAutoBatterySaverSuggestion(context);
119                 }
120             }
121 
122             return true;
123         }
124         return false;
125     }
126 
maybeShowBatterySaverConfirmation(Context context)127     private static boolean maybeShowBatterySaverConfirmation(Context context) {
128         if (Secure.getInt(context.getContentResolver(),
129                 Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) {
130             return false; // Already shown.
131         }
132         context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION));
133         return true;
134     }
135 
showAutoBatterySaverSuggestion(Context context)136     private static void showAutoBatterySaverSuggestion(Context context) {
137         context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_AUTO_SAVER_SUGGESTION));
138     }
139 
getSystemUiBroadcast(String action)140     private static Intent getSystemUiBroadcast(String action) {
141         final Intent i = new Intent(action);
142         i.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
143         i.setPackage(SYSUI_PACKAGE);
144         return i;
145     }
146 
setBatterySaverConfirmationAcknowledged(Context context)147     private static void setBatterySaverConfirmationAcknowledged(Context context) {
148         Secure.putInt(context.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1);
149     }
150 
151     /**
152      * Don't show the automatic battery suggestion notification in the future.
153      */
suppressAutoBatterySaver(Context context)154     public static void suppressAutoBatterySaver(Context context) {
155         Secure.putInt(context.getContentResolver(),
156                 Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 1);
157     }
158 
159     /**
160      * Set the automatic battery saver trigger level to {@code level}.
161      */
setAutoBatterySaverTriggerLevel(Context context, int level)162     public static void setAutoBatterySaverTriggerLevel(Context context, int level) {
163         if (level > 0) {
164             suppressAutoBatterySaver(context);
165         }
166         Global.putInt(context.getContentResolver(), Global.LOW_POWER_MODE_TRIGGER_LEVEL, level);
167     }
168 
169     /**
170      * Set the automatic battery saver trigger level to {@code level}, but only when
171      * automatic battery saver isn't enabled yet.
172      */
ensureAutoBatterySaver(Context context, int level)173     public static void ensureAutoBatterySaver(Context context, int level) {
174         if (Global.getInt(context.getContentResolver(), Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0)
175                 == 0) {
176             setAutoBatterySaverTriggerLevel(context, level);
177         }
178     }
179 }
180