haptic feedback added

This commit is contained in:
serso 2011-10-26 23:56:45 +04:00
parent 76c0ef8397
commit eaed3d8419
11 changed files with 289 additions and 43 deletions

View File

@ -5,6 +5,8 @@
a:versionCode="5"
a:versionName="1.1.3">
<uses-permission a:name="android.permission.VIBRATE"/>
<uses-sdk a:minSdkVersion="4"
a:targetSdkVersion="8"/>

View File

@ -12,6 +12,8 @@
<!--PREFERENCE ACTIVITY-->
<string name="c_prefs_main_category">Основные настройки</string>
<string name="c_prefs_calculations_category">Настроцки вычислений</string>
<string name="c_prefs_appearance_category">Настройки внешнего вида</string>
<string name="c_prefs_drag_button_category">Настройки кнопок</string>
@ -97,4 +99,7 @@
<string name="p_layout_calculator">Калькулятор</string>
<string name="c_calc_layout_summary">Устанавливает раскладку кнопок</string>
<string name="c_calc_haptic_feedback_title">Тактильный ввод</string>
<string name="c_calc_haptic_feedback_summary">Включает/выключает вибрацию по нажатию клавиши</string>
</resources>

View File

@ -19,13 +19,16 @@
<string name="p_calc_color_display_key">org.solovyev.android.calculator.CalculatorModel_color_display</string>
<string name="p_calc_color_display">true</string>
<string name="p_calc_haptic_feedback_key">org.solovyev.android.calculator.CalculatorModel_haptic_feedback</string>
<string name="p_calc_haptic_feedback">false</string>
<string name="p_calc_vars">org.solovyev.android.calculator.CalculatorModel_vars</string>
<string name="p_calc_theme_key">org.solovyev.android.calculator.CalculatorActivity_calc_theme</string>
<string name="p_calc_theme">default_theme</string>
<string name="p_calc_layout_key">org.solovyev.android.calculator.CalculatorActivity_calc_layout</string>
<string name="p_calc_layout">main_cellphone</string>
<string name="p_calc_layout">main_calculator</string>
<string name="p_calc_grouping_separator_key">org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator</string>
<string name="p_calc_grouping_separator"> </string>

View File

@ -11,6 +11,8 @@
<string name="c_vars_and_constants">Variables And Constants</string>
<!--PREFERENCE ACTIVITY-->
<string name="c_prefs_main_category">Main settings</string>
<string name="c_prefs_calculations_category">Calculation settings</string>
<string name="c_prefs_appearance_category">Appearance settings</string>
<string name="c_prefs_drag_button_category">Drag buttons settings</string>
@ -81,7 +83,7 @@
<string name="p_violet_theme">Violet</string>
<string name="p_light_blue_theme">Light Blue</string>
<string name="c_calc_result_precision_summary">Precision of result value (all calculations are done with maximum precision regardless of the value of this option)</string>
<string name="c_calc_color_display_summary">Enables/disables colouring and styling in calculator editor</string>
<string name="c_calc_color_display_summary">Toggles colouring and styling in calculator editor</string>
<string name="c_calc_theme_summary">Sets the theme for calculator</string>
<string name="c_clear_history">Clear history</string>
<string name="c_simplify_instead_of_numeric">Next constants are undefined: {0}!</string>
@ -97,4 +99,7 @@
<string name="p_layout_calculator">Calculator</string>
<string name="c_calc_layout_summary">Sets layout of buttons</string>
<string name="c_calc_haptic_feedback_title">Haptic feedback</string>
<string name="c_calc_haptic_feedback_summary">Toggles vibration on button click</string>
</resources>

View File

@ -2,7 +2,7 @@
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:range="http://schemas.android.com/apk/res/org.solovyev.android.calculator">
<PreferenceCategory a:title="@string/c_prefs_main_category">
<PreferenceCategory a:title="@string/c_prefs_calculations_category">
<org.solovyev.android.view.prefs.NumberPickerDialogPreference
a:key="@string/p_calc_result_precision_key"
@ -11,17 +11,28 @@
a:defaultValue="5"
range:boundaries="0;10"/>
<ListPreference a:key="@string/p_calc_grouping_separator_key"
a:title="@string/c_calc_grouping_separator"
a:entries="@array/p_grouping_separator_names"
a:summary="@string/c_calc_grouping_separator_summary"
a:entryValues="@array/p_grouping_separator_values"/>
</PreferenceCategory>
<PreferenceCategory a:title="@string/c_prefs_appearance_category">
<android.preference.CheckBoxPreference
a:key="@string/p_calc_color_display_key"
a:summary="@string/c_calc_color_display_summary"
a:title="@string/c_calc_color_display_title"
a:defaultValue="true"/>
<ListPreference a:key="@string/p_calc_grouping_separator_key"
a:title="@string/c_calc_grouping_separator"
a:entries="@array/p_grouping_separator_names"
a:summary="@string/c_calc_grouping_separator_summary"
a:entryValues="@array/p_grouping_separator_values"/>
<android.preference.CheckBoxPreference
a:key="@string/p_calc_haptic_feedback_key"
a:summary="@string/c_calc_haptic_feedback_summary"
a:title="@string/c_calc_haptic_feedback_title"
a:defaultValue="false"/>
<ListPreference a:key="@string/p_calc_theme_key"
a:title="@string/c_calc_theme"
@ -59,7 +70,6 @@
a:defaultValue="0;45"
range:steps="5"
range:boundaries="0;45"/>-->
</PreferenceCategory>
</PreferenceScreen>

View File

@ -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<DragPreferencesChangeListener> dpclRegister = new Announcer<DragPreferencesChangeListener>(DragPreferencesChangeListener.class);
@ -61,6 +65,12 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
// ids of drag buttons in R.class
private List<Integer> dragButtonIds = null;
// ids of buttons in R.class
private List<Integer> 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<CalculatorHistoryState>(this.calculatorModel), dragPreferences);
final OnDragListener historyOnDragListener = new OnDragListenerVibrator(newOnDragListener(new HistoryDragProcessor<CalculatorHistoryState>(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);
@ -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<Integer>();
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<String, Integer> 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<Integer>();
buttonIds = new ArrayList<Integer>();
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) {

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}