1 /*
2  * Copyright (C) 2019 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.tv.settings.device.display.daydream;
18 
19 import static android.provider.Settings.Secure.ATTENTIVE_TIMEOUT;
20 import static android.provider.Settings.Secure.SLEEP_TIMEOUT;
21 
22 import static com.android.tv.settings.util.InstrumentationUtils.logEntrySelected;
23 
24 import android.app.tvsettings.TvSettingsEnums;
25 import android.os.Bundle;
26 import android.provider.Settings;
27 import android.text.format.DateUtils;
28 
29 import androidx.annotation.Keep;
30 import androidx.preference.ListPreference;
31 import androidx.preference.Preference;
32 import androidx.preference.SwitchPreference;
33 
34 import com.android.internal.logging.nano.MetricsProto;
35 import com.android.tv.settings.R;
36 import com.android.tv.settings.SettingsPreferenceFragment;
37 
38 /**
39  * The energy saver screen in TV settings.
40  */
41 @Keep
42 public class EnergySaverFragment extends SettingsPreferenceFragment implements
43         Preference.OnPreferenceChangeListener {
44     private static final String TAG = "EnergySaverFragment";
45     private static final String KEY_SLEEP_TIME = "sleepTime";
46     private static final String KEY_ALLOW_TURN_SCREEN_OFF = "allowTurnScreenOff";
47     private static final int DEFAULT_SLEEP_TIME_MS = (int) (24 * DateUtils.HOUR_IN_MILLIS);
48     private SwitchPreference mAllowTurnScreenOffWithWakeLockPref;
49     private ListPreference mSleepTimePref;
50 
51     @Override
onCreatePreferences(Bundle bundle, String s)52     public void onCreatePreferences(Bundle bundle, String s) {
53         setPreferencesFromResource(R.xml.energy_saver, null);
54         mAllowTurnScreenOffWithWakeLockPref = findPreference(KEY_ALLOW_TURN_SCREEN_OFF);
55         mAllowTurnScreenOffWithWakeLockPref.setOnPreferenceChangeListener(this);
56         mAllowTurnScreenOffWithWakeLockPref.setVisible(showStandbyTimeout());
57         updateAllowTurnScreenOffWithWakeLockPref();
58         mSleepTimePref = findPreference(KEY_SLEEP_TIME);
59         if (allowTurnOffWithWakeLock()) {
60             int validatedAttentiveSleepTime = getValidatedTimeout(getAttentiveSleepTime());
61             mSleepTimePref.setValue(String.valueOf(validatedAttentiveSleepTime));
62             if (getAttentiveSleepTime() != validatedAttentiveSleepTime) {
63                 setAttentiveSleepTime(validatedAttentiveSleepTime);
64             }
65         } else {
66             int validatedSleepTime = getValidatedTimeout(getSleepTime());
67             mSleepTimePref.setValue(String.valueOf(validatedSleepTime));
68             if (getSleepTime() != validatedSleepTime) {
69                 setSleepTime(validatedSleepTime);
70             }
71         }
72         mSleepTimePref.setOnPreferenceChangeListener(this);
73         mSleepTimePref.setOnPreferenceClickListener(
74                 preference -> {
75                     logEntrySelected(TvSettingsEnums.SYSTEM_ENERGYSAVER_START_DELAY);
76                     return false;
77                 });
78     }
79 
showStandbyTimeout()80     private boolean showStandbyTimeout() {
81         return getResources().getBoolean(R.bool.config_show_standby_timeout);
82     }
83 
allowTurnOffWithWakeLock()84     private boolean allowTurnOffWithWakeLock() {
85         return showStandbyTimeout() && mAllowTurnScreenOffWithWakeLockPref.isChecked();
86     }
87 
updateAllowTurnScreenOffWithWakeLockPref()88     private void updateAllowTurnScreenOffWithWakeLockPref() {
89         if (!mAllowTurnScreenOffWithWakeLockPref.isVisible()) {
90             return;
91         }
92         if (getSleepTime() == -1) {
93             mAllowTurnScreenOffWithWakeLockPref.setChecked(false);
94             mAllowTurnScreenOffWithWakeLockPref.setEnabled(false);
95         } else if (getAttentiveSleepTime() == -1) {
96             mAllowTurnScreenOffWithWakeLockPref.setChecked(false);
97             mAllowTurnScreenOffWithWakeLockPref.setEnabled(true);
98         } else {
99             mAllowTurnScreenOffWithWakeLockPref.setChecked(true);
100             mAllowTurnScreenOffWithWakeLockPref.setEnabled(true);
101         }
102     }
103 
104     @Override
getMetricsCategory()105     public int getMetricsCategory() {
106         return MetricsProto.MetricsEvent.DREAM;
107     }
108 
109     @Override
onPreferenceChange(Preference preference, Object newValue)110     public boolean onPreferenceChange(Preference preference, Object newValue) {
111         switch (preference.getKey()) {
112             case KEY_SLEEP_TIME:
113                 final int newSleepTime = Integer.parseInt((String) newValue);
114                 if (getSleepTimeEntryId(newSleepTime) != -1) {
115                     logEntrySelected(getSleepTimeEntryId(newSleepTime));
116                 }
117                 updateTimeOut(allowTurnOffWithWakeLock(), newSleepTime);
118                 break;
119             case KEY_ALLOW_TURN_SCREEN_OFF:
120                 updateTimeOut((boolean) newValue, Integer.parseInt(mSleepTimePref.getValue()));
121                 break;
122         }
123         return true;
124     }
125 
updateTimeOut(boolean allowTurnScreenOffWithWakeLock, int value)126     private void updateTimeOut(boolean allowTurnScreenOffWithWakeLock, int value) {
127         if (allowTurnScreenOffWithWakeLock) {
128             setSleepTime(value);
129             if (showStandbyTimeout()) {
130                 setAttentiveSleepTime(value);
131             }
132         } else {
133             setSleepTime(value);
134             if (showStandbyTimeout()) {
135                 setAttentiveSleepTime(-1);
136             }
137         }
138         updateAllowTurnScreenOffWithWakeLockPref();
139     }
140 
getSleepTime()141     private int getSleepTime() {
142         return Settings.Secure.getInt(getActivity().getContentResolver(), SLEEP_TIMEOUT,
143                 DEFAULT_SLEEP_TIME_MS);
144     }
145 
getAttentiveSleepTime()146     private int getAttentiveSleepTime() {
147         return Settings.Secure.getInt(getActivity().getContentResolver(), ATTENTIVE_TIMEOUT,
148                 DEFAULT_SLEEP_TIME_MS);
149     }
150 
setSleepTime(int ms)151     private void setSleepTime(int ms) {
152         Settings.Secure.putInt(getActivity().getContentResolver(), SLEEP_TIMEOUT, ms);
153     }
154 
setAttentiveSleepTime(int ms)155     private void setAttentiveSleepTime(int ms) {
156         Settings.Secure.putInt(getActivity().getContentResolver(), ATTENTIVE_TIMEOUT, ms);
157     }
158 
159     // The SLEEP_TIMEOUT and ATTENTIVE_TIMEOUT could be defined in overlay by OEMs. We validate the
160     // value to make sure that we select from the predefined options. If the value from overlay is
161     // not one of the predefined options, we round it to the closest predefined value, except -1.
getValidatedTimeout(int purposedTimeout)162     private int getValidatedTimeout(int purposedTimeout) {
163         int validatedTimeout = DEFAULT_SLEEP_TIME_MS;
164         if (purposedTimeout < 0) {
165             return -1;
166         }
167         String[] optionsString = getResources().getStringArray(R.array.screen_off_timeout_values);
168         // Find the value from the predefined values that is closest to the proposed value except -1
169         int diff = Integer.MAX_VALUE;
170         for (String option : optionsString) {
171             if (Integer.parseInt(option) != -1) {
172                 int currentDiff = Math.abs(purposedTimeout - Integer.parseInt(option));
173                 if (currentDiff < diff) {
174                     diff = currentDiff;
175                     validatedTimeout = Integer.parseInt(option);
176                 }
177             }
178         }
179         return validatedTimeout;
180     }
181 
182     // TODO(b/158783050): update logging for new options 4H, 8H, 24H.
183     // Map @array/screen_off_timeout_entries to defined log enum
getSleepTimeEntryId(int sleepTimeValue)184     private int getSleepTimeEntryId(int sleepTimeValue) {
185         switch(sleepTimeValue) {
186             case -1:
187                 return TvSettingsEnums.SYSTEM_ENERGYSAVER_START_DELAY_NEVER;
188             case 900000:
189                 return TvSettingsEnums.SYSTEM_ENERGYSAVER_START_DELAY_15M;
190             case 1800000:
191                 return TvSettingsEnums.SYSTEM_ENERGYSAVER_START_DELAY_30M;
192             case 3600000:
193                 return TvSettingsEnums.SYSTEM_ENERGYSAVER_START_DELAY_1H;
194             case 43200000:
195                 return TvSettingsEnums.SYSTEM_ENERGYSAVER_START_DELAY_12H;
196             default:
197                 return -1;
198         }
199     }
200 
201     @Override
getPageId()202     protected int getPageId() {
203         return TvSettingsEnums.SYSTEM_ENERGYSAVER;
204     }
205 }
206