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.settings.fuelgauge.batterysaver;
18 
19 import android.app.settings.SettingsEnums;
20 import android.content.Context;
21 import android.database.ContentObserver;
22 import android.graphics.Color;
23 import android.graphics.drawable.ColorDrawable;
24 import android.graphics.drawable.Drawable;
25 import android.net.Uri;
26 import android.os.AsyncTask;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.provider.Settings;
30 import android.text.TextUtils;
31 import android.view.View;
32 
33 import androidx.annotation.NonNull;
34 import androidx.annotation.Nullable;
35 import androidx.annotation.VisibleForTesting;
36 import androidx.preference.PreferenceScreen;
37 
38 import com.android.settings.R;
39 import com.android.settings.overlay.FeatureFactory;
40 import com.android.settings.widget.RadioButtonPickerFragment;
41 import com.android.settingslib.fuelgauge.BatterySaverUtils;
42 import com.android.settingslib.widget.CandidateInfo;
43 import com.android.settingslib.widget.RadioButtonPreference;
44 
45 import com.google.common.collect.Lists;
46 
47 import java.util.List;
48 
49 /**
50  * Fragment that allows users to customize their automatic battery saver mode settings.
51  *
52  * Location: Settings > Battery > Battery Saver > Set a Schedule
53  * See {@link BatterySaverSchedulePreferenceController} for the controller that manages navigation
54  * to this screen from "Settings > Battery > Battery Saver" and the summary.
55  * See {@link BatterySaverScheduleRadioButtonsController} &
56  * {@link BatterySaverScheduleSeekBarController} for the controller that manages user
57  * interactions in this screen.
58  */
59 public class BatterySaverScheduleSettings extends RadioButtonPickerFragment {
60 
61     public BatterySaverScheduleRadioButtonsController mRadioButtonController;
62     @VisibleForTesting
63     Context mContext;
64     private int mSaverPercentage;
65     private String mSaverScheduleKey;
66     private BatterySaverScheduleSeekBarController mSeekBarController;
67 
68     @VisibleForTesting
69     final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
70         @Override
71         public void onChange(boolean selfChange, Uri uri) {
72             getPreferenceScreen().removeAll();
73             updateCandidates();
74         }
75     };
76 
77     @Override
getPreferenceScreenResId()78     protected int getPreferenceScreenResId() {
79         return R.xml.battery_saver_schedule_settings;
80     }
81 
82     @Override
onAttach(Context context)83     public void onAttach(Context context) {
84         super.onAttach(context);
85         mSeekBarController = new BatterySaverScheduleSeekBarController(context);
86         mRadioButtonController = new BatterySaverScheduleRadioButtonsController(
87                 context, mSeekBarController);
88         mContext = context;
89     }
90 
91     @Override
onResume()92     public void onResume() {
93         super.onResume();
94         mContext.getContentResolver().registerContentObserver(
95                 Settings.Secure.getUriFor(Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED),
96                 false,
97                 mSettingsObserver);
98         mSaverScheduleKey = mRadioButtonController.getDefaultKey();
99         mSaverPercentage = getSaverPercentage();
100     }
101 
102     @Override
onViewCreated(@onNull View view, @Nullable Bundle savedInstanceState)103     public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
104         super.onViewCreated(view, savedInstanceState);
105         setDivider(new ColorDrawable(Color.TRANSPARENT));
106         setDividerHeight(0);
107     }
108 
109     @Override
onCreate(Bundle savedInstanceState)110     public void onCreate(Bundle savedInstanceState) {
111         super.onCreate(savedInstanceState);
112     }
113 
114     @Override
onPause()115     public void onPause() {
116         mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
117         AsyncTask.execute(() -> logPowerSaver());
118         super.onPause();
119     }
120 
121     @Override
getCandidates()122     protected List<? extends CandidateInfo> getCandidates() {
123         Context context = getContext();
124         List<CandidateInfo> candidates = Lists.newArrayList();
125         String routineProviderApp = getContext().getResources()
126                 .getString(com.android.internal.R.string.config_batterySaverScheduleProvider);
127         candidates.add(new BatterySaverScheduleCandidateInfo(
128                 context.getText(R.string.battery_saver_auto_no_schedule),
129                 /* summary */ null,
130                 BatterySaverScheduleRadioButtonsController.KEY_NO_SCHEDULE,
131                 /* enabled */ true));
132         // only add routine option if an app has been specified
133         if (!TextUtils.isEmpty(routineProviderApp)) {
134             candidates.add(new BatterySaverScheduleCandidateInfo(
135                     context.getText(R.string.battery_saver_auto_routine),
136                     context.getText(R.string.battery_saver_auto_routine_summary),
137                     BatterySaverScheduleRadioButtonsController.KEY_ROUTINE,
138                     /* enabled */ true));
139         } else {
140             // Make sure routine is not selected if no provider app is configured
141             BatterySaverUtils.revertScheduleToNoneIfNeeded(context);
142         }
143         candidates.add(new BatterySaverScheduleCandidateInfo(
144                 context.getText(R.string.battery_saver_auto_percentage),
145                 /* summary */ null,
146                 BatterySaverScheduleRadioButtonsController.KEY_PERCENTAGE,
147                 /* enabled */ true));
148 
149         return candidates;
150     }
151 
152     @Override
bindPreferenceExtra(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey, String systemDefaultKey)153     public void bindPreferenceExtra(RadioButtonPreference pref, String key, CandidateInfo info,
154             String defaultKey, String systemDefaultKey) {
155         final BatterySaverScheduleCandidateInfo candidateInfo =
156                 (BatterySaverScheduleCandidateInfo) info;
157         final CharSequence summary = candidateInfo.getSummary();
158         if (summary != null) {
159             pref.setSummary(summary);
160             pref.setAppendixVisibility(View.GONE);
161         }
162     }
163 
164     @Override
addStaticPreferences(PreferenceScreen screen)165     protected void addStaticPreferences(PreferenceScreen screen) {
166         mSeekBarController.updateSeekBar();
167         mSeekBarController.addToScreen(screen);
168     }
169 
170     @Override
getDefaultKey()171     protected String getDefaultKey() {
172         return mRadioButtonController.getDefaultKey();
173     }
174 
175     @Override
setDefaultKey(String key)176     protected boolean setDefaultKey(String key) {
177         return mRadioButtonController.setDefaultKey(key);
178     }
179 
180     @Override
getMetricsCategory()181     public int getMetricsCategory() {
182         return 0;
183     }
184 
logPowerSaver()185     private void logPowerSaver() {
186         final int currentSaverPercentage = getSaverPercentage();
187         final String currentSaverScheduleKey = mRadioButtonController.getDefaultKey();
188         if (mSaverScheduleKey.equals(currentSaverScheduleKey)
189                 && mSaverPercentage == currentSaverPercentage) {
190             return;
191         }
192         FeatureFactory.getFactory(mContext).getMetricsFeatureProvider()
193                 .action(SettingsEnums.FUELGAUGE_BATTERY_SAVER,
194                         SettingsEnums.FIELD_BATTERY_SAVER_SCHEDULE_TYPE,
195                         SettingsEnums.FIELD_BATTERY_SAVER_PERCENTAGE_VALUE,
196                         currentSaverScheduleKey,
197                         currentSaverPercentage);
198     }
199 
getSaverPercentage()200     private int getSaverPercentage() {
201         return Settings.Global.getInt(mContext.getContentResolver(),
202                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1);
203     }
204 
205     static class BatterySaverScheduleCandidateInfo extends CandidateInfo {
206 
207         private final CharSequence mLabel;
208         private final CharSequence mSummary;
209         private final String mKey;
210 
BatterySaverScheduleCandidateInfo(CharSequence label, CharSequence summary, String key, boolean enabled)211         BatterySaverScheduleCandidateInfo(CharSequence label, CharSequence summary, String key,
212                 boolean enabled) {
213             super(enabled);
214             mLabel = label;
215             mKey = key;
216             mSummary = summary;
217         }
218 
219         @Override
loadLabel()220         public CharSequence loadLabel() {
221             return mLabel;
222         }
223 
224         @Override
loadIcon()225         public Drawable loadIcon() {
226             return null;
227         }
228 
229         @Override
getKey()230         public String getKey() {
231             return mKey;
232         }
233 
getSummary()234         public CharSequence getSummary() {
235             return mSummary;
236         }
237     }
238 }
239