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