From 311867dad76122c6738eea5fc10274f9f948124b Mon Sep 17 00:00:00 2001 From: serso Date: Wed, 26 Oct 2011 23:56:45 +0400 Subject: [PATCH] haptic feedback added --- AndroidManifest.xml | 2 + res/values-ru/strings.xml | 5 + res/values/default_values.xml | 5 +- res/values/strings.xml | 7 +- res/xml/main_preferences.xml | 24 ++-- .../calculator/CalculatorActivity.java | 112 ++++++++++++------ .../android/view/widgets/ColorButton.java | 24 ++++ .../view/widgets/OnClickListenerVibrator.java | 36 ++++++ .../view/widgets/OnClickListenerWrapper.java | 30 +++++ .../view/widgets/OnDragListenerWrapper.java | 34 ++++++ .../view/widgets/VibratorContainer.java | 53 +++++++++ 11 files changed, 289 insertions(+), 43 deletions(-) create mode 100644 src/main/java/org/solovyev/android/view/widgets/OnClickListenerVibrator.java create mode 100644 src/main/java/org/solovyev/android/view/widgets/OnClickListenerWrapper.java create mode 100644 src/main/java/org/solovyev/android/view/widgets/OnDragListenerWrapper.java create mode 100644 src/main/java/org/solovyev/android/view/widgets/VibratorContainer.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 01d26edd..05de47c6 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5,6 +5,8 @@ a:versionCode="5" a:versionName="1.1.3"> + + diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index aa7fe8e8..52702a9e 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -12,6 +12,8 @@ Основные настройки + Настроцки вычислений + Настройки внешнего вида Настройки кнопок @@ -97,4 +99,7 @@ Калькулятор Устанавливает раскладку кнопок + Тактильный ввод + Включает/выключает вибрацию по нажатию клавиши + diff --git a/res/values/default_values.xml b/res/values/default_values.xml index 649f8d77..0e269f30 100644 --- a/res/values/default_values.xml +++ b/res/values/default_values.xml @@ -19,13 +19,16 @@ org.solovyev.android.calculator.CalculatorModel_color_display true + org.solovyev.android.calculator.CalculatorModel_haptic_feedback + false + org.solovyev.android.calculator.CalculatorModel_vars org.solovyev.android.calculator.CalculatorActivity_calc_theme default_theme org.solovyev.android.calculator.CalculatorActivity_calc_layout - main_cellphone + main_calculator org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator diff --git a/res/values/strings.xml b/res/values/strings.xml index 8e29e53d..ff9dc258 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11,6 +11,8 @@ Variables And Constants Main settings + Calculation settings + Appearance settings Drag buttons settings @@ -81,7 +83,7 @@ Violet Light Blue Precision of result value (all calculations are done with maximum precision regardless of the value of this option) - Enables/disables colouring and styling in calculator editor + Toggles colouring and styling in calculator editor Sets the theme for calculator Clear history Next constants are undefined: {0}! @@ -97,4 +99,7 @@ Calculator Sets layout of buttons + Haptic feedback + Toggles vibration on button click + diff --git a/res/xml/main_preferences.xml b/res/xml/main_preferences.xml index 2812e567..e29b6125 100644 --- a/res/xml/main_preferences.xml +++ b/res/xml/main_preferences.xml @@ -2,7 +2,7 @@ - + + + + + + + + - + --> - \ No newline at end of file diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java index 37b5d2d1..d0defba6 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java @@ -12,12 +12,14 @@ import android.content.Intent; import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; +import android.os.Vibrator; import android.preference.PreferenceManager; import android.text.ClipboardManager; import android.text.method.LinkMovementMethod; import android.util.Log; import android.util.TypedValue; import android.view.*; +import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import bsh.EvalError; @@ -41,6 +43,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh private static final int HVGA_WIDTH_PIXELS = 320; + private static final long ON_CLICK_VIBRATION_TIME = 100; + @NotNull private final Announcer dpclRegister = new Announcer(DragPreferencesChangeListener.class); @@ -61,6 +65,12 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh // ids of drag buttons in R.class private List dragButtonIds = null; + // ids of buttons in R.class + private List buttonIds = null; + + @Nullable + private Vibrator vibrator; + /** * Called when the activity is first created. */ @@ -78,28 +88,27 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh firstTimeInit(preferences); + vibrator = (Vibrator) this.getSystemService(VIBRATOR_SERVICE); + calculatorModel = CalculatorModel.instance.init(this, preferences, CalculatorEngine.instance); dpclRegister.clear(); final SimpleOnDragListener.Preferences dragPreferences = SimpleOnDragListener.getPreferences(preferences, this); - setOnDragListeners(dragPreferences); + setOnDragListeners(dragPreferences, preferences); - final SimpleOnDragListener historyOnDragListener = new SimpleOnDragListener(new HistoryDragProcessor(this.calculatorModel), dragPreferences); + final OnDragListener historyOnDragListener = new OnDragListenerVibrator(newOnDragListener(new HistoryDragProcessor(this.calculatorModel), dragPreferences), vibrator, preferences); ((DragButton) findViewById(R.id.historyButton)).setOnDragListener(historyOnDragListener); - dpclRegister.addListener(historyOnDragListener); - final SimpleOnDragListener toPositionOnDragListener = new SimpleOnDragListener(new CursorDragProcessor(calculatorModel), dragPreferences); + final OnDragListener toPositionOnDragListener = new OnDragListenerVibrator(new SimpleOnDragListener(new CursorDragProcessor(calculatorModel), dragPreferences), vibrator, preferences); ((DragButton) findViewById(R.id.rightButton)).setOnDragListener(toPositionOnDragListener); ((DragButton) findViewById(R.id.leftButton)).setOnDragListener(toPositionOnDragListener); - dpclRegister.addListener(toPositionOnDragListener); final DragButton equalsButton = (DragButton) findViewById(R.id.equalsButton); if (equalsButton != null) { - final SimpleOnDragListener evalOnDragListener = new SimpleOnDragListener(new EvalDragProcessor(calculatorModel), dragPreferences); + final OnDragListener evalOnDragListener = new OnDragListenerVibrator(newOnDragListener(new EvalDragProcessor(calculatorModel), dragPreferences), vibrator, preferences); equalsButton.setOnDragListener(evalOnDragListener); - dpclRegister.addListener(evalOnDragListener); } CalculatorEngine.instance.reset(this, preferences); @@ -108,13 +117,13 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh } private void setDefaultValues(@NotNull SharedPreferences preferences) { - if ( !preferences.contains(CalculatorEngine.GROUPING_SEPARATOR_P_KEY) ) { + if (!preferences.contains(CalculatorEngine.GROUPING_SEPARATOR_P_KEY)) { final Locale locale = Locale.getDefault(); - if ( locale != null ) { + if (locale != null) { final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(locale); int index = MathType.grouping_separator.getTokens().indexOf(String.valueOf(decimalFormatSymbols.getGroupingSeparator())); final String groupingSeparator; - if ( index >= 0 ) { + if (index >= 0) { groupingSeparator = MathType.grouping_separator.getTokens().get(index); } else { groupingSeparator = " "; @@ -126,34 +135,48 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh } } - private synchronized void setOnDragListeners(@NotNull SimpleOnDragListener.Preferences dragPreferences) { - final SimpleOnDragListener onDragListener = new SimpleOnDragListener(new DigitButtonDragProcessor(calculatorModel), dragPreferences); - dpclRegister.addListener(onDragListener); - - if (dragButtonIds == null) { - dragButtonIds = new ArrayList(); - - for (Field field : R.id.class.getDeclaredFields()) { - int modifiers = field.getModifiers(); - if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) { - try { - int dragButtonId = field.getInt(R.id.class); - final View view = findViewById(dragButtonId); - if (view instanceof DragButton) { - dragButtonIds.add(dragButtonId); - } - } catch (IllegalAccessException e) { - Log.e(CalculatorActivity.class.getName(), e.getMessage()); - } - } - } - } + private synchronized void setOnDragListeners(@NotNull SimpleOnDragListener.Preferences dragPreferences, @NotNull SharedPreferences preferences) { + final OnDragListener onDragListener = new OnDragListenerVibrator(newOnDragListener(new DigitButtonDragProcessor(calculatorModel), dragPreferences), vibrator, preferences); for (Integer dragButtonId : dragButtonIds) { ((DragButton) findViewById(dragButtonId)).setOnDragListener(onDragListener); } } + @NotNull + private SimpleOnDragListener newOnDragListener(@NotNull SimpleOnDragListener.DragProcessor dragProcessor, + @NotNull SimpleOnDragListener.Preferences dragPreferences) { + final SimpleOnDragListener onDragListener = new SimpleOnDragListener(dragProcessor, dragPreferences); + dpclRegister.addListener(onDragListener); + return onDragListener; + } + + private class OnDragListenerVibrator extends OnDragListenerWrapper { + + private static final long VIBRATION_TIME = 50; + + @NotNull + private final VibratorContainer vibrator; + + public OnDragListenerVibrator(@NotNull OnDragListener onDragListener, + @Nullable Vibrator vibrator, + @NotNull SharedPreferences preferences) { + super(onDragListener); + this.vibrator = new VibratorContainer(vibrator, preferences, VIBRATION_TIME); + } + + @Override + public boolean onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event) { + boolean result = super.onDrag(dragButton, event); + + if (result) { + vibrator.vibrate(); + } + + return result; + } + } + private synchronized void setLayout(@NotNull SharedPreferences preferences) { final Map layouts = getCache(R.layout.class); @@ -162,8 +185,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh Integer layoutId = layouts.get(layoutName); if (layoutId == null) { - Log.d(this.getClass().getName(), "No saved layout found => applying default layout: " + R.layout.main_cellphone); - layoutId = R.layout.main_cellphone; + Log.d(this.getClass().getName(), "No saved layout found => applying default layout: " + R.layout.main_calculator); + layoutId = R.layout.main_calculator; } else { Log.d(this.getClass().getName(), "Saved layout found: " + layoutId); } @@ -213,6 +236,27 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh private synchronized void firstTimeInit(@NotNull SharedPreferences preferences) { if (!initialized) { + dragButtonIds = new ArrayList(); + buttonIds = new ArrayList(); + + for (Field field : R.id.class.getDeclaredFields()) { + int modifiers = field.getModifiers(); + if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) { + try { + int viewId = field.getInt(R.id.class); + final View view = findViewById(viewId); + if (view instanceof DragButton) { + dragButtonIds.add(viewId); + } + if (view instanceof Button) { + buttonIds.add(viewId); + } + } catch (IllegalAccessException e) { + Log.e(CalculatorActivity.class.getName(), e.getMessage()); + } + } + } + try { CalculatorEngine.instance.init(this, preferences); } catch (EvalError evalError) { diff --git a/src/main/java/org/solovyev/android/view/widgets/ColorButton.java b/src/main/java/org/solovyev/android/view/widgets/ColorButton.java index caa10219..92b54b51 100644 --- a/src/main/java/org/solovyev/android/view/widgets/ColorButton.java +++ b/src/main/java/org/solovyev/android/view/widgets/ColorButton.java @@ -27,6 +27,8 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.drawable.Drawable; +import android.os.Vibrator; +import android.preference.PreferenceManager; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.Button; @@ -54,15 +56,21 @@ public class ColorButton extends Button { private long animationStart; private Paint feedbackPaint; + @NotNull + private final OnClickListenerVibrator onClickListener; + public ColorButton(Context context, AttributeSet attrs) { this(context, attrs, true); } public ColorButton(Context context, AttributeSet attrs, boolean init) { super(context, attrs); + if (init) { init(context); } + + this.onClickListener = new OnClickListenerVibrator((Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE), PreferenceManager.getDefaultSharedPreferences(context)); } protected void init(Context context) { @@ -179,6 +187,22 @@ public class ColorButton extends Button { invalidate(); } + @Override + public boolean performClick() { + vibrate(); + return super.performClick(); + } + + @Override + public boolean performLongClick() { + vibrate(); + return super.performLongClick(); + } + + private void vibrate() { + this.onClickListener.onClick(this); + } + @Override public boolean onTouchEvent(MotionEvent event) { boolean result = super.onTouchEvent(event); diff --git a/src/main/java/org/solovyev/android/view/widgets/OnClickListenerVibrator.java b/src/main/java/org/solovyev/android/view/widgets/OnClickListenerVibrator.java new file mode 100644 index 00000000..39c30103 --- /dev/null +++ b/src/main/java/org/solovyev/android/view/widgets/OnClickListenerVibrator.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.view.widgets; + +import android.content.SharedPreferences; +import android.os.Vibrator; +import android.view.View; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** +* User: serso +* Date: 10/26/11 +* Time: 11:25 PM +*/ +public class OnClickListenerVibrator implements View.OnClickListener { + + private static final long VIBRATION_TIME = 100; + + @NotNull + private VibratorContainer vibrator; + + public OnClickListenerVibrator(@Nullable Vibrator vibrator, + @NotNull SharedPreferences preferences) { + this.vibrator = new VibratorContainer(vibrator, preferences, VIBRATION_TIME); + } + + @Override + public void onClick(View v) { + vibrator.vibrate(); + } +} diff --git a/src/main/java/org/solovyev/android/view/widgets/OnClickListenerWrapper.java b/src/main/java/org/solovyev/android/view/widgets/OnClickListenerWrapper.java new file mode 100644 index 00000000..e68243f9 --- /dev/null +++ b/src/main/java/org/solovyev/android/view/widgets/OnClickListenerWrapper.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.view.widgets; + +import android.view.View; +import org.jetbrains.annotations.NotNull; + +/** + * User: serso + * Date: 10/26/11 + * Time: 10:55 PM + */ +public class OnClickListenerWrapper implements View.OnClickListener{ + + @NotNull + private final View.OnClickListener onClickListener; + + public OnClickListenerWrapper(@NotNull View.OnClickListener onClickListener) { + this.onClickListener = onClickListener; + } + + @Override + public void onClick(View v) { + this.onClick(v); + } +} diff --git a/src/main/java/org/solovyev/android/view/widgets/OnDragListenerWrapper.java b/src/main/java/org/solovyev/android/view/widgets/OnDragListenerWrapper.java new file mode 100644 index 00000000..f88c8220 --- /dev/null +++ b/src/main/java/org/solovyev/android/view/widgets/OnDragListenerWrapper.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.view.widgets; + +import org.jetbrains.annotations.NotNull; + +/** +* User: serso +* Date: 10/26/11 +* Time: 10:37 PM +*/ +public class OnDragListenerWrapper implements OnDragListener { + + @NotNull + private final OnDragListener onDragListener; + + public OnDragListenerWrapper(@NotNull OnDragListener onDragListener) { + this.onDragListener = onDragListener; + } + + @Override + public boolean isSuppressOnClickEvent() { + return this.onDragListener.isSuppressOnClickEvent(); + } + + @Override + public boolean onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event) { + return this.onDragListener.onDrag(dragButton, event); + } +} diff --git a/src/main/java/org/solovyev/android/view/widgets/VibratorContainer.java b/src/main/java/org/solovyev/android/view/widgets/VibratorContainer.java new file mode 100644 index 00000000..09999560 --- /dev/null +++ b/src/main/java/org/solovyev/android/view/widgets/VibratorContainer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.view.widgets; + +import android.content.SharedPreferences; +import android.os.Vibrator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: serso + * Date: 10/26/11 + * Time: 11:40 PM + */ +public class VibratorContainer implements SharedPreferences.OnSharedPreferenceChangeListener { + + private static final String HAPTIC_FEEDBACK_PREFERENCE = "org.solovyev.android.calculator.CalculatorModel_haptic_feedback"; + + private final long defaultVibrationTime; + + @Nullable + private final Vibrator vibrator; + + private long time = 0; + + public VibratorContainer(@Nullable Vibrator vibrator, @NotNull SharedPreferences preferences, long defaultVibrationTime) { + this.vibrator = vibrator; + this.defaultVibrationTime = defaultVibrationTime; + + preferences.registerOnSharedPreferenceChangeListener(this); + onSharedPreferenceChanged(preferences, null); + + } + + public void vibrate() { + if (time > 0 && vibrator != null) { + vibrator.vibrate(time); + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences preferences, @Nullable String key) { + if (preferences.getBoolean(HAPTIC_FEEDBACK_PREFERENCE, false)) { + this.time = defaultVibrationTime; + } else { + this.time = 0; + } + } +}