12df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka/*
22df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka * Copyright (C) 2013 The Android Open Source Project
32df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
72df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
92df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka *
102df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License.
152df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka */
162df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
17a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasapackage com.android.inputmethod.latin.settings;
182df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
192df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokaimport android.app.AlertDialog;
202df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokaimport android.content.Context;
212df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokaimport android.content.DialogInterface;
222df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokaimport android.content.res.TypedArray;
232df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokaimport android.preference.DialogPreference;
242df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokaimport android.util.AttributeSet;
252df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokaimport android.view.View;
262df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokaimport android.widget.SeekBar;
272df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokaimport android.widget.TextView;
282df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
29a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.R;
30a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasa
312df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaokapublic final class SeekBarDialogPreference extends DialogPreference
322df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        implements SeekBar.OnSeekBarChangeListener {
332df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    public interface ValueProxy {
342df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        public int readValue(final String key);
352df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        public int readDefaultValue(final String key);
362df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        public void writeValue(final int value, final String key);
37d99abf8cb119ff2cb4e7d975001a939cc48d7112Tadashi G. Takaoka        public void writeDefaultValue(final String key);
383be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        public String getValueText(final int value);
392df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        public void feedbackValue(final int value);
402df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    }
412df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
422df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    private final int mMaxValue;
43c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    private final int mMinValue;
44c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    private final int mStepValue;
452df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
462df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    private TextView mValueView;
472df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    private SeekBar mSeekBar;
482df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
492df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    private ValueProxy mValueProxy;
502df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
512df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    public SeekBarDialogPreference(final Context context, final AttributeSet attrs) {
522df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        super(context, attrs);
532df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        final TypedArray a = context.obtainStyledAttributes(
542df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka                attrs, R.styleable.SeekBarDialogPreference, 0, 0);
552df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        mMaxValue = a.getInt(R.styleable.SeekBarDialogPreference_maxValue, 0);
56c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        mMinValue = a.getInt(R.styleable.SeekBarDialogPreference_minValue, 0);
57c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        mStepValue = a.getInt(R.styleable.SeekBarDialogPreference_stepValue, 0);
582df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        a.recycle();
592df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        setDialogLayoutResource(R.layout.seek_bar_dialog);
602df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    }
612df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
622df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    public void setInterface(final ValueProxy proxy) {
632df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        mValueProxy = proxy;
643be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        final int value = mValueProxy.readValue(getKey());
653be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        setSummary(mValueProxy.getValueText(value));
662df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    }
672df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
682df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    @Override
692df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    protected View onCreateDialogView() {
702df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        final View view = super.onCreateDialogView();
712df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        mSeekBar = (SeekBar)view.findViewById(R.id.seek_bar_dialog_bar);
72c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        mSeekBar.setMax(mMaxValue - mMinValue);
732df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        mSeekBar.setOnSeekBarChangeListener(this);
742df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        mValueView = (TextView)view.findViewById(R.id.seek_bar_dialog_value);
752df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        return view;
762df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    }
772df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
78c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    private int getProgressFromValue(final int value) {
79c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        return value - mMinValue;
80c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    }
81c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka
82c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    private int getValueFromProgress(final int progress) {
83c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        return progress + mMinValue;
84c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    }
85c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka
86c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    private int clipValue(final int value) {
87c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        final int clippedValue = Math.min(mMaxValue, Math.max(mMinValue, value));
88c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        if (mStepValue <= 1) {
89c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka            return clippedValue;
90c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        }
91c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        return clippedValue - (clippedValue % mStepValue);
92c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    }
93c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka
94c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    private int getClippedValueFromProgress(final int progress) {
95c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        return clipValue(getValueFromProgress(progress));
96c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka    }
97c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka
982df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    @Override
992df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    protected void onBindDialogView(final View view) {
1003be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        final int value = mValueProxy.readValue(getKey());
1013be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        mValueView.setText(mValueProxy.getValueText(value));
1023be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        mSeekBar.setProgress(getProgressFromValue(clipValue(value)));
1032df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    }
1042df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
1052df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    @Override
1062df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    protected void onPrepareDialogBuilder(final AlertDialog.Builder builder) {
1072df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        builder.setPositiveButton(android.R.string.ok, this)
1082df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka            .setNegativeButton(android.R.string.cancel, this)
1092df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka            .setNeutralButton(R.string.button_default, this);
1102df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    }
1112df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
1122df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    @Override
1132df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    public void onClick(final DialogInterface dialog, final int which) {
1142df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        super.onClick(dialog, which);
115d99abf8cb119ff2cb4e7d975001a939cc48d7112Tadashi G. Takaoka        final String key = getKey();
1162df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        if (which == DialogInterface.BUTTON_NEUTRAL) {
1173be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka            final int value = mValueProxy.readDefaultValue(key);
1183be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka            setSummary(mValueProxy.getValueText(value));
119d99abf8cb119ff2cb4e7d975001a939cc48d7112Tadashi G. Takaoka            mValueProxy.writeDefaultValue(key);
120d99abf8cb119ff2cb4e7d975001a939cc48d7112Tadashi G. Takaoka            return;
1212df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        }
122d99abf8cb119ff2cb4e7d975001a939cc48d7112Tadashi G. Takaoka        if (which == DialogInterface.BUTTON_POSITIVE) {
1233be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka            final int value = getClippedValueFromProgress(mSeekBar.getProgress());
1243be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka            setSummary(mValueProxy.getValueText(value));
1253be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka            mValueProxy.writeValue(value, key);
126d99abf8cb119ff2cb4e7d975001a939cc48d7112Tadashi G. Takaoka            return;
1272df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka        }
1282df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    }
1292df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
1302df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    @Override
1312df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    public void onProgressChanged(final SeekBar seekBar, final int progress,
1322df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka            final boolean fromUser) {
1333be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        final int value = getClippedValueFromProgress(progress);
1343be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        mValueView.setText(mValueProxy.getValueText(value));
1353be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        if (!fromUser) {
1363be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka            mSeekBar.setProgress(getProgressFromValue(value));
1373be8263035b69226aba90fe1f1e4e4c3484ffe3dTadashi G. Takaoka        }
1382df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    }
1392df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
1402df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    @Override
1412df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    public void onStartTrackingTouch(final SeekBar seekBar) {}
1422df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka
1432df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    @Override
1442df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    public void onStopTrackingTouch(final SeekBar seekBar) {
145c053293484cd872ee305703886f09c66876fbae7Tadashi G. Takaoka        mValueProxy.feedbackValue(getClippedValueFromProgress(seekBar.getProgress()));
1462df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka    }
1472df0cf2c5a0142a4274bafee6cd53540ac7a1ce9Tadashi G. Takaoka}
148