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