1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14package com.android.tv.quicksettings;
15
16import android.content.SharedPreferences;
17import android.preference.PreferenceManager;
18import android.support.annotation.NonNull;
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.content.DialogInterface;
22import android.content.Intent;
23import android.os.Bundle;
24import android.support.v17.leanback.widget.OnChildSelectedListener;
25import android.support.v17.leanback.widget.VerticalGridView;
26import android.util.Log;
27import android.view.Gravity;
28import android.view.KeyEvent;
29import android.view.View;
30import android.view.ViewGroup;
31import android.view.WindowManager;
32import android.widget.SeekBar;
33import android.widget.TextView;
34
35import java.util.ArrayList;
36import java.util.Arrays;
37
38public class SettingsDialog extends Activity {
39
40    private static final int PRESET_SETTING_INDEX = 0;
41    private static final int INTEGER_SETTING_START_INDEX = 1;
42
43    private static final String TAG = "SettingsDialog";
44    private static final boolean DEBUG = true;
45
46    static final String EXTRA_START_POS = "com.android.tv.quicksettings.START_POS";
47    private static final int SETTING_INT_VALUE_MIN = 0;
48    private static final int SETTING_INT_VALUE_STEP = 10;
49
50    private VerticalGridView mPanelList;
51    private SeekBar mSeekBar;
52    private TextView mSettingValue;
53    private DialogAdapter mAdapter;
54    private final SettingSelectedListener mSettingSelectedListener = new SettingSelectedListener();
55    private Setting mFocusedSetting;
56    private ArrayList<Setting> mSettings;
57    private SharedPreferences mSharedPreferences;
58
59    private PresetSettingsListener mPresetSettingsListener;
60
61    @Override
62    public void onCreate(Bundle savedInstanceState) {
63        super.onCreate(savedInstanceState);
64
65        mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
66        mPresetSettingsListener = new PresetSettingsListener(this);
67
68        WindowManager.LayoutParams lp = getWindow().getAttributes();
69        lp.height = WindowManager.LayoutParams.MATCH_PARENT;
70        lp.gravity = Gravity.BOTTOM | Gravity.CENTER;
71        lp.y = getResources().getDimensionPixelSize(R.dimen.panel_y_offset);
72        getWindow().setAttributes(lp);
73
74        setContentView(R.layout.main_quicksettings);
75
76        Intent intent = getIntent();
77        int startPos = intent.getIntExtra(EXTRA_START_POS, -1);
78        if (DEBUG)
79            Log.d(TAG, "startPos=" + startPos);
80
81        mPanelList = (VerticalGridView) findViewById(R.id.main_panel_list);
82        mPanelList.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
83        mPanelList.setOnChildSelectedListener(mSettingSelectedListener);
84
85        mSettings = getSettings();
86
87        final int pivotX;
88        if (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
89            pivotX = getResources().getDimensionPixelSize(R.dimen.slider_horizontal_padding);
90        } else {
91            pivotX = getResources().getDimensionPixelSize(
92                    R.dimen.main_panel_text_width_minus_padding);
93        }
94        final int pivotY = getResources().getDimensionPixelSize(R.dimen.main_panel_text_height_half);
95
96        mAdapter = new DialogAdapter(mSettings, pivotX, pivotY, new SettingClickedListener() {
97            @Override
98            public void onSettingClicked(Setting s) {
99                if (s.getType() != Setting.TYPE_UNKNOWN) {
100                    finish();
101                } else {
102                    new AlertDialog.Builder(SettingsDialog.this).setPositiveButton(
103                            android.R.string.ok, new DialogInterface.OnClickListener() {
104                                @Override
105                                public void onClick(DialogInterface dialog, int id) {
106                                    // User clicked OK button
107                                    String[] presetSettingValues = getResources().getStringArray(
108                                            R.array.setting_preset_values);
109                                    mSettings.get(PRESET_SETTING_INDEX).setValue(
110                                            presetSettingValues[getResources().getInteger(
111                                                    R.integer.standard_setting_index)]);
112                                }
113                            }).setNegativeButton(android.R.string.cancel,
114                            new DialogInterface.OnClickListener() {
115                                @Override
116                                public void onClick(DialogInterface dialog, int id) {
117                                    // User cancelled the dialog - do nothing
118                                }
119                            }).setTitle(R.string.reset_dialog_message).create().show();
120                }
121            }
122        });
123
124        mPanelList.setAdapter(mAdapter);
125        mPanelList.setSelectedPosition(startPos + 1);
126        mPanelList.requestFocus();
127
128        mSeekBar = (SeekBar) findViewById(R.id.main_slider);
129
130        mSettingValue = (TextView) findViewById(R.id.setting_value);
131    }
132
133    @Override
134    protected void onResume() {
135        super.onResume();
136
137        mSharedPreferences.registerOnSharedPreferenceChangeListener(mPresetSettingsListener);
138    }
139
140    @Override
141    protected void onPause() {
142        super.onPause();
143
144        mSharedPreferences.unregisterOnSharedPreferenceChangeListener(mPresetSettingsListener);
145    }
146
147    private ArrayList<Setting> getSettings() {
148        ArrayList<Setting> settings = new ArrayList<>();
149
150        settings.add(new Setting(mSharedPreferences, "preset",
151                getString(R.string.setting_preset_name)));
152
153        String[] settingNames = getResources().getStringArray(R.array.setting_names);
154        String[] settingKeys = getResources().getStringArray(R.array.setting_keys);
155        int[] maxSettingValues = getResources().getIntArray(R.array.setting_max_values);
156        for (int i = 0; i < settingNames.length; i++) {
157            settings.add(
158                    new Setting(mSharedPreferences, settingKeys[i], settingNames[i],
159                            maxSettingValues[i]));
160        }
161        settings.add(new Setting(getString(R.string.setting_reset_defaults_name)));
162
163        return settings;
164    }
165
166    private class SettingSelectedListener implements OnChildSelectedListener {
167        @Override
168        public void onChildSelected(ViewGroup parent, View view, int position, long id) {
169            mFocusedSetting = mSettings.get(position);
170            switch (mFocusedSetting.getType()) {
171                case Setting.TYPE_STRING:
172                    mSettingValue.setVisibility(View.VISIBLE);
173                    mSettingValue.setText(mFocusedSetting.getStringValue());
174                    mSeekBar.setVisibility(View.GONE);
175                    break;
176                case Setting.TYPE_INT:
177                    mSettingValue.setVisibility(View.VISIBLE);
178                    mSettingValue.setText(Integer.toString(mFocusedSetting.getIntValue()));
179                    mSeekBar.setMax(mFocusedSetting.getMaxValue());
180                    mSeekBar.setProgress(mFocusedSetting.getIntValue());
181                    mSeekBar.setVisibility(View.VISIBLE);
182                    break;
183                default:
184                    mSettingValue.setVisibility(View.GONE);
185                    mSeekBar.setVisibility(View.GONE);
186                    break;
187            }
188        }
189    }
190
191    @Override
192    public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
193        if (mFocusedSetting == null) {
194            return super.onKeyUp(keyCode, event);
195        }
196        switch (mFocusedSetting.getType()) {
197            case Setting.TYPE_INT:
198                return integerSettingHandleKeyCode(keyCode, event);
199            case Setting.TYPE_STRING:
200                return stringSettingHandleKeyCode(keyCode, event);
201            default:
202                return super.onKeyUp(keyCode, event);
203        }
204    }
205
206    private boolean integerSettingHandleKeyCode(int keyCode, KeyEvent event) {
207        switch (keyCode) {
208            case KeyEvent.KEYCODE_DPAD_RIGHT:
209                setFocusedSettingToValue(Math.min(
210                        mFocusedSetting.getIntValue() + SETTING_INT_VALUE_STEP,
211                        mFocusedSetting.getMaxValue()));
212                return true;
213            case KeyEvent.KEYCODE_DPAD_LEFT:
214                setFocusedSettingToValue(Math.max(
215                        mFocusedSetting.getIntValue() - SETTING_INT_VALUE_STEP,
216                        SETTING_INT_VALUE_MIN));
217                return true;
218            default:
219                return super.onKeyUp(keyCode, event);
220        }
221    }
222
223    private void setFocusedSettingToValue(int value) {
224        mFocusedSetting.setValue(value);
225        mSeekBar.setProgress(mFocusedSetting.getIntValue());
226        mSettingValue.setText(Integer.toString(mFocusedSetting.getIntValue()));
227        String[] presetSettingChoices = getResources().getStringArray(
228                R.array.setting_preset_values);
229        mSettings.get(PRESET_SETTING_INDEX).setValue(
230                presetSettingChoices[getResources().getInteger(R.integer.custom_setting_index)]);
231    }
232
233    private boolean stringSettingHandleKeyCode(int keyCode, KeyEvent event) {
234        if (!mFocusedSetting.getTitle().equals(getString(R.string.setting_preset_name))) {
235            return super.onKeyUp(keyCode, event);
236        }
237
238        String[] presetSettingChoices = getResources().getStringArray(
239                R.array.setting_preset_choices);
240        String[] presetSettingValues = getResources().getStringArray(R.array.setting_preset_values);
241
242        int currentIndex = Arrays.asList(presetSettingValues).indexOf(
243                mFocusedSetting.getStringValue());
244        switch (keyCode) {
245            case KeyEvent.KEYCODE_DPAD_RIGHT:
246                currentIndex++;
247                break;
248            case KeyEvent.KEYCODE_DPAD_LEFT:
249                currentIndex--;
250                break;
251            default:
252                return super.onKeyUp(keyCode, event);
253        }
254        int newIndex = (currentIndex + presetSettingValues.length) % presetSettingValues.length;
255        mFocusedSetting.setValue(presetSettingValues[newIndex]);
256        mSettingValue.setText(presetSettingChoices[newIndex]);
257        int[] newSettingValues = null;
258        if (newIndex == getResources().getInteger(R.integer.standard_setting_index)) {
259            newSettingValues = getResources().getIntArray(R.array.standard_setting_values);
260        } else if (newIndex == getResources().getInteger(R.integer.cinema_setting_index)) {
261            newSettingValues = getResources().getIntArray(R.array.cinema_setting_values);
262        } else if (newIndex == getResources().getInteger(R.integer.vivid_setting_index)) {
263            newSettingValues = getResources().getIntArray(R.array.vivid_setting_values);
264        } else if (newIndex == getResources().getInteger(R.integer.game_setting_index)) {
265            newSettingValues = getResources().getIntArray(R.array.game_setting_values);
266        }
267        if (newSettingValues != null) {
268            for (int i = 0; i < newSettingValues.length; i++) {
269                mSettings.get(i + INTEGER_SETTING_START_INDEX).setValue(
270                        newSettingValues[i]);
271            }
272        }
273        return true;
274    }
275}
276