1 /*
2  * Copyright (C) 2015 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.System.SCREEN_OFF_TIMEOUT;
20 
21 import static com.android.tv.settings.overlay.FlavorUtils.FLAVOR_CLASSIC;
22 import static com.android.tv.settings.overlay.FlavorUtils.FLAVOR_TWO_PANEL;
23 import static com.android.tv.settings.overlay.FlavorUtils.FLAVOR_VENDOR;
24 import static com.android.tv.settings.overlay.FlavorUtils.FLAVOR_X;
25 import static com.android.tv.settings.util.InstrumentationUtils.logEntrySelected;
26 
27 import android.app.tvsettings.TvSettingsEnums;
28 import android.content.BroadcastReceiver;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.os.Bundle;
34 import android.os.UserManager;
35 import android.provider.Settings;
36 import android.text.format.DateUtils;
37 import android.util.ArrayMap;
38 import android.util.Log;
39 
40 import androidx.annotation.Keep;
41 import androidx.preference.ListPreference;
42 import androidx.preference.Preference;
43 
44 import com.android.settingslib.dream.DreamBackend;
45 import com.android.tv.settings.R;
46 import com.android.tv.settings.RestrictedPreferenceAdapter;
47 import com.android.tv.settings.SettingsPreferenceFragment;
48 import com.android.tv.settings.overlay.FlavorUtils;
49 
50 import java.util.List;
51 import java.util.Map;
52 import java.util.Objects;
53 
54 /**
55  * The screen saver screen in TV settings.
56  */
57 @Keep
58 public class DaydreamFragment extends SettingsPreferenceFragment
59         implements Preference.OnPreferenceChangeListener {
60 
61     private static final String TAG = "DaydreamFragment";
62 
63     private static final String KEY_ACTIVE_DREAM = "activeDream";
64     private static final String KEY_DREAM_TIME = "dreamTime";
65     private static final String KEY_DREAM_NOW = "dreamNow";
66 
67     private static final String DREAM_COMPONENT_NONE = "NONE";
68     private static final String PACKAGE_SCHEME = "package";
69 
70     private static final int DEFAULT_DREAM_TIME_MS = (int) (30 * DateUtils.MINUTE_IN_MILLIS);
71 
72     private final PackageReceiver mPackageReceiver = new PackageReceiver();
73 
74     private DreamBackend mBackend;
75     private final Map<String, DreamBackend.DreamInfo> mDreamInfos = new ArrayMap<>();
76 
77     private RestrictedPreferenceAdapter<ListPreference> mActiveDreamPref;
78     private RestrictedPreferenceAdapter<ListPreference> mDreamTimePref;
79 
newInstance()80     public static DaydreamFragment newInstance() {
81         return new DaydreamFragment();
82     }
83 
84     @Override
onCreate(Bundle savedInstanceState)85     public void onCreate(Bundle savedInstanceState) {
86         mBackend = new DreamBackend(getActivity());
87         super.onCreate(savedInstanceState);
88     }
89 
90     @Override
onResume()91     public void onResume() {
92         super.onResume();
93         refreshFromBackend();
94 
95         // listen for package changes
96         IntentFilter filter = new IntentFilter();
97         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
98         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
99         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
100         filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
101         filter.addDataScheme(PACKAGE_SCHEME);
102         getActivity().registerReceiver(mPackageReceiver, filter);
103     }
104 
105     @Override
onPause()106     public void onPause() {
107         super.onPause();
108 
109         getActivity().unregisterReceiver(mPackageReceiver);
110     }
111 
112 
getPreferenceScreenResId()113     private int getPreferenceScreenResId() {
114         switch (FlavorUtils.getFlavor(getContext())) {
115             case FLAVOR_CLASSIC:
116             case FLAVOR_TWO_PANEL:
117                 return R.xml.daydream;
118             case FLAVOR_X:
119             case FLAVOR_VENDOR:
120                 return R.xml.daydream_x;
121             default:
122                 return R.xml.daydream;
123         }
124     }
125 
126     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)127     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
128         setPreferencesFromResource(getPreferenceScreenResId(), null);
129         final String userRestriction = UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT;
130 
131         final ListPreference activeDreamPref = (ListPreference) findPreference(KEY_ACTIVE_DREAM);
132         refreshActiveDreamPref();
133         if (activeDreamPref != null) {
134             activeDreamPref.setOnPreferenceChangeListener(this);
135             mActiveDreamPref = RestrictedPreferenceAdapter.adapt(activeDreamPref, userRestriction);
136         }
137 
138         final ListPreference dreamTimePref = (ListPreference) findPreference(KEY_DREAM_TIME);
139         if (dreamTimePref != null) {
140             dreamTimePref.setValue(Integer.toString(getDreamTime()));
141             dreamTimePref.setOnPreferenceChangeListener(this);
142             mDreamTimePref = RestrictedPreferenceAdapter.adapt(dreamTimePref, userRestriction);
143         }
144 
145         final Preference dreamNowPref = findPreference(KEY_DREAM_NOW);
146         dreamNowPref.setEnabled(mBackend.isEnabled());
147     }
148 
refreshActiveDreamPref()149     private void refreshActiveDreamPref() {
150         if (mActiveDreamPref == null) {
151             return;
152         }
153 
154         final List<DreamBackend.DreamInfo> infos = mBackend.getDreamInfos();
155         final CharSequence[] dreamEntries = new CharSequence[infos.size() + 1];
156         final CharSequence[] dreamEntryValues = new CharSequence[infos.size() + 1];
157         refreshDreamInfoMap(infos, dreamEntries, dreamEntryValues);
158         final ComponentName currentDreamComponent = mBackend.getActiveDream();
159 
160         mActiveDreamPref.updatePreference(activeDreamPref -> {
161             activeDreamPref.setEntries(dreamEntries);
162             activeDreamPref.setEntryValues(dreamEntryValues);
163             activeDreamPref.setValue(mBackend.isEnabled() && currentDreamComponent != null
164                     ? currentDreamComponent.toShortString() : DREAM_COMPONENT_NONE);
165         });
166     }
167 
refreshDreamInfoMap(List<DreamBackend.DreamInfo> infos, CharSequence[] listEntries, CharSequence[] listEntryValues)168     private void refreshDreamInfoMap(List<DreamBackend.DreamInfo> infos,
169             CharSequence[] listEntries, CharSequence[] listEntryValues) {
170         mDreamInfos.clear();
171         listEntries[0] = getString(R.string.device_daydreams_none);
172         listEntryValues[0] = DREAM_COMPONENT_NONE;
173         int index = 1;
174         for (final DreamBackend.DreamInfo info : infos) {
175             final String componentNameString = info.componentName.toShortString();
176             mDreamInfos.put(componentNameString, info);
177             listEntries[index] = info.caption;
178             listEntryValues[index] = componentNameString;
179             index++;
180         }
181     }
182 
183     @Override
onPreferenceChange(Preference preference, Object newValue)184     public boolean onPreferenceChange(Preference preference, Object newValue) {
185         switch (preference.getKey()) {
186             case KEY_ACTIVE_DREAM:
187                 logEntrySelected(TvSettingsEnums.PREFERENCES_SCREENSAVER_CHOOSER);
188                 setActiveDream((String) newValue);
189                 break;
190             case KEY_DREAM_TIME:
191                 final int sleepTimeout = Integer.parseInt((String) newValue);
192                 if (getSleepTimeoutEntryId(sleepTimeout) != -1) {
193                     logEntrySelected(getSleepTimeoutEntryId(sleepTimeout));
194                 }
195                 setDreamTime(sleepTimeout);
196                 break;
197         }
198         return true;
199     }
200 
setActiveDream(String componentNameString)201     private void setActiveDream(String componentNameString) {
202         final DreamBackend.DreamInfo dreamInfo = mDreamInfos.get(componentNameString);
203         if (dreamInfo != null) {
204             if (dreamInfo.settingsComponentName != null) {
205                 startActivity(new Intent().setComponent(dreamInfo.settingsComponentName));
206             }
207             if (!mBackend.isEnabled()) {
208                 mBackend.setEnabled(true);
209             }
210             if (!Objects.equals(mBackend.getActiveDream(), dreamInfo.componentName)) {
211                 mBackend.setActiveDream(dreamInfo.componentName);
212             }
213         } else {
214             if (mBackend.isEnabled()) {
215                 mBackend.setActiveDream(null);
216                 mBackend.setEnabled(false);
217             }
218         }
219     }
220 
getDreamTime()221     private int getDreamTime() {
222         return Settings.System.getInt(getActivity().getContentResolver(), SCREEN_OFF_TIMEOUT,
223                 DEFAULT_DREAM_TIME_MS);
224     }
225 
setDreamTime(int ms)226     private void setDreamTime(int ms) {
227         Settings.System.putInt(getActivity().getContentResolver(), SCREEN_OFF_TIMEOUT, ms);
228     }
229 
230     @Override
onPreferenceTreeClick(Preference preference)231     public boolean onPreferenceTreeClick(Preference preference) {
232         switch (preference.getKey()) {
233             case KEY_DREAM_NOW:
234                 logEntrySelected(TvSettingsEnums.PREFERENCES_SCREENSAVER_START_NOW);
235                 mBackend.startDreaming();
236                 return true;
237             default:
238                 return super.onPreferenceTreeClick(preference);
239         }
240     }
241 
refreshFromBackend()242     private void refreshFromBackend() {
243         if (getActivity() == null) {
244             Log.d(TAG, "No activity, not refreshing");
245             return;
246         }
247 
248         refreshActiveDreamPref();
249         if (mDreamTimePref != null) {
250             mDreamTimePref.updatePreference(
251                     dreamTimePref -> dreamTimePref.setValue(Integer.toString(getDreamTime())));
252         }
253 
254         final Preference dreamNowPref = findPreference(KEY_DREAM_NOW);
255         if (dreamNowPref != null) {
256             dreamNowPref.setEnabled(mBackend.isEnabled());
257         }
258     }
259 
260     private class PackageReceiver extends BroadcastReceiver {
261         @Override
onReceive(Context context, Intent intent)262         public void onReceive(Context context, Intent intent) {
263             refreshFromBackend();
264         }
265     }
266 
267     // Map @array/sleep_timeout_entries to defined log enum
getSleepTimeoutEntryId(int sleepTimeout)268     private int getSleepTimeoutEntryId(int sleepTimeout) {
269         switch(sleepTimeout) {
270             case 300000:
271                 return TvSettingsEnums.PREFERENCES_SCREENSAVER_START_DELAY_5M;
272             case 900000:
273                 return TvSettingsEnums.PREFERENCES_SCREENSAVER_START_DELAY_15M;
274             case 1800000:
275                 return TvSettingsEnums.PREFERENCES_SCREENSAVER_START_DELAY_30M;
276             case 3600000:
277                 return TvSettingsEnums.PREFERENCES_SCREENSAVER_START_DELAY_1H;
278             case 7200000:
279                 return TvSettingsEnums.PREFERENCES_SCREENSAVER_START_DELAY_2H;
280             default:
281                 return -1;
282         }
283     }
284 
285     @Override
getPageId()286     protected int getPageId() {
287         return TvSettingsEnums.PREFERENCES_SCREENSAVER;
288     }
289 }
290