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