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