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