1 /*
2  * Copyright (C) 2016 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.system;
18 
19 import android.content.Context;
20 import android.hardware.hdmi.HdmiControlManager;
21 import android.icu.text.MessageFormat;
22 import android.media.tv.TvInputInfo;
23 import android.media.tv.TvInputManager;
24 import android.os.Bundle;
25 import android.os.UserHandle;
26 import android.text.TextUtils;
27 
28 import androidx.annotation.Keep;
29 import androidx.preference.Preference;
30 import androidx.preference.PreferenceGroup;
31 import androidx.preference.TwoStatePreference;
32 
33 import com.android.tv.settings.R;
34 import com.android.tv.settings.SettingsPreferenceFragment;
35 
36 import java.util.HashMap;
37 import java.util.Locale;
38 import java.util.Map;
39 import java.util.Set;
40 
41 /**
42  * Fragment to control TV input settings.
43  */
44 @Keep
45 public class InputsFragment extends SettingsPreferenceFragment {
46 
47     private static final String KEY_CONNECTED_INPUTS = "connected_inputs";
48     private static final String KEY_STANDBY_INPUTS = "standby_inputs";
49     private static final String KEY_DISCONNECTED_INPUTS = "disconnected_inputs";
50     private static final String KEY_HDMI_CONTROL = "hdmi_control";
51     private static final String KEY_DEVICE_AUTO_OFF = "device_auto_off";
52     private static final String KEY_TV_AUTO_ON = "tv_auto_on";
53     private static final String ICU_PLURAL_COUNT = "count";
54 
55     private PreferenceGroup mConnectedGroup;
56     private PreferenceGroup mStandbyGroup;
57     private PreferenceGroup mDisconnectedGroup;
58 
59     private TwoStatePreference mHdmiControlPref;
60     private TwoStatePreference mDeviceAutoOffPref;
61     private TwoStatePreference mTvAutoOnPref;
62 
63     private TvInputManager mTvInputManager;
64     private HdmiControlManager mHdmiControlManager;
65     private Map<String, String> mCustomLabels;
66     private Set<String> mHiddenIds;
67 
newInstance()68     public static InputsFragment newInstance() {
69         return new InputsFragment();
70     }
71 
72     @Override
onCreate(Bundle savedInstanceState)73     public void onCreate(Bundle savedInstanceState) {
74         super.onCreate(savedInstanceState);
75         mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
76         mHdmiControlManager = getContext().getSystemService(HdmiControlManager.class);
77     }
78 
79     @Override
onResume()80     public void onResume() {
81         super.onResume();
82         final Context context = getContext();
83         mCustomLabels =
84                 TvInputInfo.TvInputSettings.getCustomLabels(context, UserHandle.USER_SYSTEM);
85         mHiddenIds =
86                 TvInputInfo.TvInputSettings.getHiddenTvInputIds(context, UserHandle.USER_SYSTEM);
87         refresh();
88     }
89 
90     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)91     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
92         setPreferencesFromResource(R.xml.inputs, null);
93 
94         mConnectedGroup = (PreferenceGroup) findPreference(KEY_CONNECTED_INPUTS);
95         mStandbyGroup = (PreferenceGroup) findPreference(KEY_STANDBY_INPUTS);
96         mDisconnectedGroup = (PreferenceGroup) findPreference(KEY_DISCONNECTED_INPUTS);
97 
98         mHdmiControlPref = (TwoStatePreference) findPreference(KEY_HDMI_CONTROL);
99         mDeviceAutoOffPref = (TwoStatePreference) findPreference(KEY_DEVICE_AUTO_OFF);
100         mTvAutoOnPref = (TwoStatePreference) findPreference(KEY_TV_AUTO_ON);
101     }
102 
refresh()103     private void refresh() {
104         mHdmiControlPref.setChecked(mHdmiControlManager.getHdmiCecEnabled()
105                 == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
106         mDeviceAutoOffPref.setChecked(mHdmiControlManager.getTvSendStandbyOnSleep()
107                 == HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED);
108         mTvAutoOnPref.setChecked(mHdmiControlManager.getTvWakeOnOneTouchPlay()
109                 == HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED);
110 
111         for (TvInputInfo info : mTvInputManager.getTvInputList()) {
112             if (info.getType() == TvInputInfo.TYPE_TUNER
113                     || !TextUtils.isEmpty(info.getParentId())) {
114                 continue;
115             }
116 
117             int state;
118             try {
119                 state = mTvInputManager.getInputState(info.getId());
120             } catch (IllegalArgumentException e) {
121                 // Input is gone while iterating. Ignore.
122                 continue;
123             }
124 
125             InputPreference inputPref = (InputPreference) findPreference(makeInputPrefKey(info));
126             if (inputPref == null) {
127                 inputPref = new InputPreference(getPreferenceManager().getContext());
128             }
129             inputPref.refresh(info);
130 
131             switch (state) {
132                 case TvInputManager.INPUT_STATE_CONNECTED:
133                     mStandbyGroup.removePreference(inputPref);
134                     mDisconnectedGroup.removePreference(inputPref);
135                     mConnectedGroup.addPreference(inputPref);
136                     break;
137                 case TvInputManager.INPUT_STATE_CONNECTED_STANDBY:
138                     mConnectedGroup.removePreference(inputPref);
139                     mDisconnectedGroup.removePreference(inputPref);
140                     mStandbyGroup.addPreference(inputPref);
141                     break;
142                 case TvInputManager.INPUT_STATE_DISCONNECTED:
143                     mConnectedGroup.removePreference(inputPref);
144                     mStandbyGroup.removePreference(inputPref);
145                     mDisconnectedGroup.addPreference(inputPref);
146                     break;
147             }
148         }
149 
150         final int connectedCount = mConnectedGroup.getPreferenceCount();
151         MessageFormat msgFormat = new MessageFormat(
152                 getResources().getString(R.string.inputs_header_connected_input),
153                 Locale.getDefault());
154         Map<String, Object> arguments = new HashMap<>();
155         arguments.put(ICU_PLURAL_COUNT, connectedCount);
156         String songsFound = msgFormat.format(arguments);
157         mConnectedGroup.setTitle(msgFormat.format(arguments));
158         mConnectedGroup.setVisible(connectedCount > 0);
159 
160         final int standbyCount = mStandbyGroup.getPreferenceCount();
161         msgFormat = new MessageFormat(
162                 getResources().getString(R.string.inputs_header_standby_input),
163                 Locale.getDefault());
164         arguments = new HashMap<>();
165         arguments.put(ICU_PLURAL_COUNT, standbyCount);
166         mStandbyGroup.setTitle(msgFormat.format(arguments));
167         mStandbyGroup.setVisible(standbyCount > 0);
168 
169         final int disconnectedCount = mDisconnectedGroup.getPreferenceCount();
170         msgFormat = new MessageFormat(
171                 getResources().getString(R.string.inputs_header_disconnected_input),
172                 Locale.getDefault());
173         arguments = new HashMap<>();
174         arguments.put(ICU_PLURAL_COUNT, disconnectedCount);
175         mDisconnectedGroup.setTitle(msgFormat.format(arguments));
176         mDisconnectedGroup.setVisible(disconnectedCount > 0);
177     }
178 
179     @Override
onPreferenceTreeClick(Preference preference)180     public boolean onPreferenceTreeClick(Preference preference) {
181         final String key = preference.getKey();
182         if (key == null) {
183             return super.onPreferenceTreeClick(preference);
184         }
185         switch (key) {
186             case KEY_HDMI_CONTROL:
187                 mHdmiControlManager.setHdmiCecEnabled(mHdmiControlPref.isChecked()
188                         ? HdmiControlManager.HDMI_CEC_CONTROL_ENABLED
189                         : HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
190                 return true;
191             case KEY_DEVICE_AUTO_OFF:
192                 mHdmiControlManager.setTvSendStandbyOnSleep(mDeviceAutoOffPref.isChecked()
193                         ? HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED
194                         : HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_DISABLED);
195                 return true;
196             case KEY_TV_AUTO_ON:
197                 mHdmiControlManager.setTvWakeOnOneTouchPlay(mTvAutoOnPref.isChecked()
198                         ? HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_ENABLED
199                         : HdmiControlManager.TV_WAKE_ON_ONE_TOUCH_PLAY_DISABLED);
200                 return true;
201         }
202         return super.onPreferenceTreeClick(preference);
203     }
204 
205     private class InputPreference extends Preference {
InputPreference(Context context)206         public InputPreference(Context context) {
207             super(context);
208         }
209 
refresh(TvInputInfo inputInfo)210         public void refresh(TvInputInfo inputInfo) {
211             setKey(makeInputPrefKey(inputInfo));
212 
213             setTitle(inputInfo.loadLabel(getContext()));
214 
215             String customLabel;
216             if (mHiddenIds.contains(inputInfo.getId())) {
217                 customLabel = getString(R.string.inputs_hide);
218             } else {
219                 customLabel = mCustomLabels.get(inputInfo.getId());
220                 if (TextUtils.isEmpty(customLabel)) {
221                     customLabel = inputInfo.loadLabel(getContext()).toString();
222                 }
223             }
224             setSummary(customLabel);
225             setFragment(InputOptionsFragment.class.getName());
226             InputOptionsFragment.prepareArgs(getExtras(), inputInfo);
227         }
228     }
229 
makeInputPrefKey(TvInputInfo inputInfo)230     public static String makeInputPrefKey(TvInputInfo inputInfo) {
231         return "InputPref:" + inputInfo.getId();
232     }
233 }
234