drag button calibration

This commit is contained in:
serso 2011-07-16 23:25:12 +04:00
parent aa512ed335
commit 70ff5a109e
15 changed files with 532 additions and 161 deletions

View File

@ -4,15 +4,20 @@
package="org.solovyev.android.calculator" package="org.solovyev.android.calculator"
versionCode="1" versionCode="1"
versionName="1.0"> versionName="1.0">
<a:uses-sdk a:minSdkVersion="8"/>
<a:application a:icon="@drawable/icon" a:label="@string/app_name_caption"> <uses-sdk a:minSdkVersion="8"/>
<a:activity a:name=".Calculator" a:label="@string/app_name_caption">
<a:intent-filter>
<a:action a:name="android.intent.action.MAIN" />
<a:category a:name="android.intent.category.LAUNCHER" />
</a:intent-filter>
</a:activity>
</a:application> <application a:icon="@drawable/icon" a:label="@string/c_app_name">
<activity a:name=".CalculatorActivity" a:label="@string/c_app_name">
<intent-filter>
<action a:name="android.intent.action.MAIN" />
<category a:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity a:name=".CalculatorPreferencesActivity" a:label="@string/c_app_settings"/>
<activity a:name=".DragButtonCalibrationActivity" a:label="@string/c_prefs_drag_button_calibration"/>
</application>
</manifest> </manifest>

View File

@ -30,43 +30,63 @@ containing a value of this type.
public static final int icon=0x7f020000; public static final int icon=0x7f020000;
} }
public static final class id { public static final class id {
public static final int curlyBracketsButton=0x7f060013; public static final int calibrationButton=0x7f080000;
public static final int editText=0x7f060000; public static final int calibrationStart=0x7f080001;
public static final int eigthDigitButton=0x7f06000f; public static final int curlyBracketsButton=0x7f080015;
public static final int equalsButton=0x7f060011; public static final int editText=0x7f080002;
public static final int fiveDigitButton=0x7f060009; public static final int eigthDigitButton=0x7f080011;
public static final int fourDigitButton=0x7f060008; public static final int equalsButton=0x7f080013;
public static final int historyButton=0x7f060018; public static final int fiveDigitButton=0x7f08000b;
public static final int minusButton=0x7f06000c; public static final int fourDigitButton=0x7f08000a;
public static final int muliplicationButton=0x7f060005; public static final int historyButton=0x7f08001a;
public static final int nineDigitButton=0x7f060010; public static final int menu_item_help=0x7f08001d;
public static final int numericButton=0x7f060016; public static final int menu_item_settings=0x7f08001c;
public static final int oneDigitButton=0x7f060002; public static final int minusButton=0x7f08000e;
public static final int piButton=0x7f060019; public static final int muliplicationButton=0x7f080007;
public static final int plusButton=0x7f060006; public static final int nineDigitButton=0x7f080012;
public static final int pointDigitButton=0x7f060015; public static final int numericButton=0x7f080018;
public static final int resultEditText=0x7f060001; public static final int oneDigitButton=0x7f080004;
public static final int roundBracketsButton=0x7f060007; public static final int piButton=0x7f08001b;
public static final int sevenDigitButton=0x7f06000e; public static final int plusButton=0x7f080008;
public static final int simplifyButton=0x7f060017; public static final int pointDigitButton=0x7f080017;
public static final int sixDigitButton=0x7f06000a; public static final int resultEditText=0x7f080003;
public static final int sqrtButton=0x7f060012; public static final int roundBracketsButton=0x7f080009;
public static final int squareBracketsButton=0x7f06000d; public static final int sevenDigitButton=0x7f080010;
public static final int subtractionButton=0x7f06000b; public static final int simplifyButton=0x7f080019;
public static final int threeDigitButton=0x7f060004; public static final int sixDigitButton=0x7f08000c;
public static final int twoDigitButton=0x7f060003; public static final int sqrtButton=0x7f080014;
public static final int zeroDigitButton=0x7f060014; public static final int squareBracketsButton=0x7f08000f;
public static final int subtractionButton=0x7f08000d;
public static final int threeDigitButton=0x7f080006;
public static final int twoDigitButton=0x7f080005;
public static final int zeroDigitButton=0x7f080016;
} }
public static final class layout { public static final class layout {
public static final int main=0x7f030000; public static final int drag_button_calibration=0x7f030000;
public static final int main=0x7f030001;
}
public static final class menu {
public static final int main_menu=0x7f070000;
} }
public static final class string { public static final class string {
public static final int app_name_caption=0x7f040000; public static final int c_app_name=0x7f050000;
public static final int syntax_error=0x7f040001; public static final int c_app_settings=0x7f050001;
public static final int c_down=0x7f050008;
public static final int c_help=0x7f050004;
public static final int c_prefs_drag_button_calibration=0x7f050006;
public static final int c_prefs_drag_button_calibration_summary=0x7f050007;
public static final int c_prefs_main_category=0x7f050005;
public static final int c_restart=0x7f05000a;
public static final int c_settings=0x7f050003;
public static final int c_up=0x7f050009;
public static final int syntax_error=0x7f050002;
} }
public static final class style { public static final class style {
public static final int digitButtonStyle=0x7f050001; public static final int digitButtonStyle=0x7f060001;
public static final int editTextInputStyle=0x7f050000; public static final int editTextInputStyle=0x7f060000;
}
public static final class xml {
public static final int preferences=0x7f040000;
} }
public static final class styleable { public static final class styleable {
/** Attributes that can be used with a DragButton. /** Attributes that can be used with a DragButton.

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:calc="http://schemas.android.com/apk/res/org.solovyev.android.calculator"
a:orientation="vertical"
a:padding="6dp"
a:layout_width="fill_parent"
a:layout_height="fill_parent">
<org.solovyev.android.view.DragButton a:id="@+id/calibrationButton"
a:text=""
calc:textUp="@string/c_up"
calc:textDown="@string/c_down"
style="@style/digitButtonStyle"
a:layout_width="50dp"
a:layout_height="50dp"
a:gravity="center_vertical" />
<Button a:id="@+id/calibrationStart"
a:text="@string/c_restart"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:onClick="restartClickHandler"
a:gravity="bottom"/>
</LinearLayout>

9
res/menu/main_menu.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:a="http://schemas.android.com/apk/res/android">
<item a:id="@+id/menu_item_settings"
a:title="@string/c_settings"/>
<item a:id="@+id/menu_item_help"
a:title="@string/c_help"/>
</menu>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name_caption">Калькулятор</string> <string name="c_app_name">Калькулятор</string>
</resources> </resources>

View File

@ -1,5 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name_caption">Calculator</string> <string name="c_app_name">Calculator</string>
<string name="c_app_settings">Calculator</string>
<string name="syntax_error">Syntax error</string> <string name="syntax_error">Syntax error</string>
<string name="c_settings">Settings</string>
<string name="c_help">Help</string>
<string name="c_prefs_main_category">Main settings</string>
<string name="c_prefs_drag_button_calibration">Drag button calibration</string>
<string name="c_prefs_drag_button_calibration_summary">Allows to calibrate drag button behaviour</string>
<string name="c_down">Down</string>
<string name="c_up">Up</string>
<string name="c_restart">Restart</string>
</resources> </resources>

20
res/xml/preferences.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android">
<PreferenceCategory a:title="@string/c_prefs_main_category">
<Preference
a:title="@string/c_prefs_drag_button_calibration"
a:summary="@string/c_prefs_drag_button_calibration_summary"
a:key="dragButtonCalibration"/>
<CheckBoxPreference
a:title="Checkbox Preference"
a:defaultValue="false"
a:summary="This preference can be true or false"
a:key="checkboxPref"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@ -3,13 +3,11 @@ package org.solovyev.android.calculator;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import android.content.Intent;
import android.view.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R; import org.solovyev.android.view.*;
import org.solovyev.android.view.DragButton;
import org.solovyev.android.view.DragEvent;
import org.solovyev.android.view.OnDragListener;
import org.solovyev.android.view.SimpleOnDragListener;
import org.solovyev.util.StringUtils; import org.solovyev.util.StringUtils;
import org.solovyev.util.math.MathEntityType; import org.solovyev.util.math.MathEntityType;
@ -19,10 +17,10 @@ import bsh.Interpreter;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import org.solovyev.util.math.Point2d;
public class Calculator extends Activity { public class CalculatorActivity extends Activity {
@NotNull @NotNull
private EditText editText; private EditText editText;
@ -36,7 +34,9 @@ public class Calculator extends Activity {
@NotNull @NotNull
private HistoryHelper<EditorHistoryState> historyHelper; private HistoryHelper<EditorHistoryState> historyHelper;
/** Called when the activity is first created. */ /**
* Called when the activity is first created.
*/
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -46,7 +46,23 @@ public class Calculator extends Activity {
this.resultEditText = (EditText) findViewById(R.id.resultEditText); this.resultEditText = (EditText) findViewById(R.id.resultEditText);
final SimpleOnDragListener onDragListener = new SimpleOnDragListener(); final SimpleOnDragListener onDragListener = new SimpleOnDragListener(new SimpleOnDragListener.DragProcessor() {
@Override
public boolean processDragEvent(@NotNull DragDirection dragDirection, @NotNull DragButton dragButton, @NotNull Point2d startPoint2d, @NotNull MotionEvent motionEvent) {
boolean result = isDirectionSupported(dragButton, dragDirection);
if (result) {
processButtonAction(dragButton, getActionText(dragButton, dragDirection));
}
return result;
}
public boolean isDirectionSupported(@NotNull DragButton dragButton, @NotNull DragDirection direction) {
return !StringUtils.isEmpty(getActionText(dragButton, direction));
}
});
// todo serso: check if there is more convenient method for doing this // todo serso: check if there is more convenient method for doing this
final R.id ids = new R.id(); final R.id ids = new R.id();
@ -59,21 +75,21 @@ public class Calculator extends Activity {
((DragButton) view).setOnDragListener(onDragListener); ((DragButton) view).setOnDragListener(onDragListener);
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.e(Calculator.class.getName(), e.getMessage()); Log.e(CalculatorActivity.class.getName(), e.getMessage());
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
Log.e(Calculator.class.getName(), e.getMessage()); Log.e(CalculatorActivity.class.getName(), e.getMessage());
} }
} }
} }
((DragButton) findViewById(R.id.historyButton)).setOnDragListener(new HistoryOnDragListener()); ((DragButton) findViewById(R.id.historyButton)).setOnDragListener(new SimpleOnDragListener(new HistoryDragProcessor()));
this.interpreter = new Interpreter(); this.interpreter = new Interpreter();
try { try {
interpreter.eval(Preprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands")); interpreter.eval(Preprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
} catch (EvalError e) { } catch (EvalError e) {
Log.e(Calculator.class.getName(), e.getMessage()); Log.e(CalculatorActivity.class.getName(), e.getMessage());
} }
this.historyHelper = new SimpleHistoryHelper<EditorHistoryState>(); this.historyHelper = new SimpleHistoryHelper<EditorHistoryState>();
@ -97,7 +113,7 @@ public class Calculator extends Activity {
final String preprocessedString = Preprocessor.process(String.valueOf(editText.getText())); final String preprocessedString = Preprocessor.process(String.valueOf(editText.getText()));
resultEditText.setText(String.valueOf(interpreter.eval(Preprocessor.wrap(operation, preprocessedString)))); resultEditText.setText(String.valueOf(interpreter.eval(Preprocessor.wrap(operation, preprocessedString))));
} catch (EvalError e) { } catch (EvalError e) {
Log.e(Calculator.class.getName(), e.getMessage()); Log.e(CalculatorActivity.class.getName(), e.getMessage());
resultEditText.setText(R.string.syntax_error); resultEditText.setText(R.string.syntax_error);
} }
} }
@ -106,16 +122,21 @@ public class Calculator extends Activity {
processButtonAction(v, ((DragButton) v).getTextMiddle()); processButtonAction(v, ((DragButton) v).getTextMiddle());
} }
private final class HistoryOnDragListener implements OnDragListener { private final class HistoryDragProcessor implements SimpleOnDragListener.DragProcessor {
@Override
public void onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event) {
Log.d(String.valueOf(dragButton.getId()), "History on drag event start: " + event.getDirection());
String actionText = getActionText(dragButton, event); @Override
public boolean processDragEvent(@NotNull DragDirection dragDirection, @NotNull DragButton dragButton, @NotNull Point2d startPoint2d, @NotNull MotionEvent motionEvent) {
boolean result = false;
Log.d(String.valueOf(dragButton.getId()), "History on drag event start: " + dragDirection);
String actionText = getActionText(dragButton, dragDirection);
if (!StringUtils.isEmpty(actionText)) { if (!StringUtils.isEmpty(actionText)) {
try { try {
result = true;
final HistoryAction historyAction = HistoryAction.valueOf(actionText); final HistoryAction historyAction = HistoryAction.valueOf(actionText);
if ( historyHelper.isActionAvailable(historyAction) ){ if (historyHelper.isActionAvailable(historyAction)) {
final EditorHistoryState newState = historyHelper.doAction(historyAction, getCurrentHistoryState()); final EditorHistoryState newState = historyHelper.doAction(historyAction, getCurrentHistoryState());
if (newState != null) { if (newState != null) {
setCurrentHistoryState(newState); setCurrentHistoryState(newState);
@ -125,14 +146,16 @@ public class Calculator extends Activity {
Log.e(String.valueOf(dragButton.getId()), "Unsupported history action: " + actionText); Log.e(String.valueOf(dragButton.getId()), "Unsupported history action: " + actionText);
} }
} }
return result;
} }
} }
@Nullable @Nullable
private static String getActionText(@NotNull DragButton dragButton, @NotNull DragEvent event) { private static String getActionText(@NotNull DragButton dragButton, @NotNull DragDirection direction) {
final String result; final String result;
switch(event.getDirection()) { switch (direction) {
case up: case up:
result = dragButton.getTextUp(); result = dragButton.getTextUp();
break; break;
@ -149,7 +172,7 @@ public class Calculator extends Activity {
return result; return result;
} }
public void setCurrentHistoryState(@Nullable EditorHistoryState editorHistoryState) { public void setCurrentHistoryState(@NotNull EditorHistoryState editorHistoryState) {
this.editText.setText(editorHistoryState.getText()); this.editText.setText(editorHistoryState.getText());
this.editText.setSelection(editorHistoryState.getCursorPosition(), editorHistoryState.getCursorPosition()); this.editText.setSelection(editorHistoryState.getCursorPosition(), editorHistoryState.getCursorPosition());
} }
@ -165,7 +188,7 @@ public class Calculator extends Activity {
} }
private void processButtonAction(@NotNull View v, @Nullable String text) { private void processButtonAction(@NotNull View v, @Nullable String text) {
//Toast.makeText(Calculator.this, text, Toast.LENGTH_SHORT).show(); //Toast.makeText(CalculatorActivity.this, text, Toast.LENGTH_SHORT).show();
if (!StringUtils.isEmpty(text)) { if (!StringUtils.isEmpty(text)) {
final MathEntityType type = MathEntityType.getType(text); final MathEntityType type = MathEntityType.getType(text);
@ -193,4 +216,37 @@ public class Calculator extends Activity {
this.historyHelper.addState(getCurrentHistoryState()); this.historyHelper.addState(getCurrentHistoryState());
} }
} }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
final MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.main_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean result;
switch (item.getItemId()) {
case R.id.menu_item_settings:
showSettings();
result = true;
case R.id.menu_item_help:
showHelp();
result = true;
default:
result = super.onOptionsItemSelected(item);
}
return result;
}
private void showSettings() {
startActivity(new Intent(this, CalculatorPreferencesActivity.class));
}
private void showHelp() {
Log.d(CalculatorActivity.class + "showHelp()", "Show help!");
}
} }

View File

@ -0,0 +1,44 @@
package org.solovyev.android.calculator;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.widget.Button;
import android.widget.Toast;
import org.apache.http.Header;
import java.security.KeyStore;
import java.util.List;
import java.util.prefs.PreferencesFactory;
/**
* User: serso
* Date: 7/16/11
* Time: 6:37 PM
*/
public class CalculatorPreferencesActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
final Preference dragButtonCalibration = findPreference("dragButtonCalibration");
dragButtonCalibration.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
startActivity(new Intent(CalculatorPreferencesActivity.this, DragButtonCalibrationActivity.class));
return true;
}
});
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
}
}

View File

@ -0,0 +1,140 @@
package org.solovyev.android.calculator;
import android.app.Activity;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.view.*;
import org.solovyev.util.math.MathUtils;
import org.solovyev.util.math.Point2d;
import java.util.ArrayList;
import java.util.List;
/**
* User: serso
* Date: 7/16/11
* Time: 7:28 PM
*/
public class DragButtonCalibrationActivity extends Activity {
@NotNull
private DragDirection dragDirection = DragDirection.up;
private final List<DragData> dragHistory = new ArrayList<DragData>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drag_button_calibration);
final DragButton calibrationButton = (DragButton) findViewById(R.id.calibrationButton);
calibrationButton.setOnDragListener(new CalibrationOnDragListener());
createDragDirection();
}
private void createDragDirection() {
dragDirection = Math.random() > 0.5 ? DragDirection.up : DragDirection.down;
Toast.makeText(this, dragDirection.name(), Toast.LENGTH_SHORT).show();
}
public void restartClickHandler(View v) {
createDragDirection();
}
private class CalibrationOnDragListener implements OnDragListener {
@Override
public boolean isSuppressOnClickEvent() {
return true;
}
@Override
public boolean onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event) {
final Point2d startPoint = event.getStartPoint();
final MotionEvent motionEvent = event.getMotionEvent();
// init end point
final Point2d endPoint = new Point2d(motionEvent.getX(), motionEvent.getY());
float distance = MathUtils.getDistance(startPoint, endPoint);
double angle = Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, SimpleOnDragListener.axis), endPoint));
assert dragDirection == DragDirection.up || dragDirection == DragDirection.down;
if (dragDirection == DragDirection.up) {
angle = 180 - angle;
}
dragHistory.add(new DragData(distance, angle, dragDirection));
createDragDirection();
return true;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
final List<Double> angleValues = new ArrayList<Double>();
final List<Double> distanceValues = new ArrayList<Double>();
for (DragData dragData : dragHistory) {
angleValues.add(dragData.getAngle());
distanceValues.add((double) dragData.getDistance());
}
double angleMean = MathUtils.countMean(angleValues);
double angleDeviation = MathUtils.countStandardDeviation(angleMean, angleValues);
double distanceMean = MathUtils.countMean(distanceValues);
double distanceDeviation = MathUtils.countStandardDeviation(distanceMean, distanceValues);
Toast.makeText(this, "Angle: m=" + angleMean + ", d=" + angleDeviation, Toast.LENGTH_SHORT).show();
Toast.makeText(this, "Distance: m=" + distanceMean + ", d=" + distanceDeviation, Toast.LENGTH_SHORT).show();
}
return super.onKeyDown(keyCode, event);
}
private class DragData {
private float distance;
private double angle;
@NotNull
private DragDirection direction;
private DragData(float distance, double angle, @NotNull DragDirection direction) {
this.distance = distance;
this.angle = angle;
this.direction = direction;
}
public float getDistance() {
return distance;
}
public double getAngle() {
return angle;
}
@NotNull
public DragDirection getDirection() {
return direction;
}
}
}

View File

@ -3,6 +3,7 @@ package org.solovyev.android.view;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.common.utils.StringsUtils;
import org.solovyev.util.StringUtils; import org.solovyev.util.StringUtils;
import org.solovyev.util.math.MathUtils; import org.solovyev.util.math.MathUtils;
import org.solovyev.util.math.Point2d; import org.solovyev.util.math.Point2d;
@ -93,26 +94,29 @@ public class DragButton extends Button {
return onDragListener; return onDragListener;
} }
public void setTextUp(String textUp) { public void setTextUp(@Nullable String textUp) {
this.textUp = textUp; this.textUp = textUp;
} }
@Nullable
public String getTextUp() { public String getTextUp() {
return textUp; return textUp;
} }
public void setTextDown(String textDown) { public void setTextDown(@Nullable String textDown) {
this.textDown = textDown; this.textDown = textDown;
} }
@Nullable
public String getTextDown() { public String getTextDown() {
return textDown; return textDown;
} }
public void setTextMiddle(String textMiddle) { public void setTextMiddle(@Nullable String textMiddle) {
this.textMiddle = textMiddle; this.textMiddle = textMiddle;
} }
@Nullable
public String getTextMiddle() { public String getTextMiddle() {
return textMiddle; return textMiddle;
} }
@ -129,7 +133,11 @@ public class DragButton extends Button {
public boolean onTouch(@NotNull View v, @NotNull MotionEvent event) { public boolean onTouch(@NotNull View v, @NotNull MotionEvent event) {
// processing on touch event // processing on touch event
if (onDragListener != null) { // in order to avoid possible NPEs
final Point2d localStartPoint = startPoint;
final OnDragListener localOnDragListener = onDragListener;
if (localOnDragListener != null) {
// only if onDrag() listener specified // only if onDrag() listener specified
Log.d(String.valueOf(getId()), "onTouch() for: " + getId() + " . Motion event: " + event); Log.d(String.valueOf(getId()), "onTouch() for: " + getId() + " . Motion event: " + event);
@ -150,8 +158,8 @@ public class DragButton extends Button {
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
// stop tracking // stop tracking
if (onDragListener.onDrag(DragButton.this, new DragEvent(startPoint, event))) { if (localStartPoint != null && localOnDragListener.onDrag(DragButton.this, new DragEvent(localStartPoint, event))) {
if (onDragListener.isSuppressOnClickEvent()) { if (localOnDragListener.isSuppressOnClickEvent()) {
// prevent on click action // prevent on click action
setPressed(false); setPressed(false);
} }

View File

@ -3,5 +3,7 @@ package org.solovyev.android.view;
public enum DragDirection { public enum DragDirection {
up, up,
down; down,
left,
right;
} }

View File

@ -18,16 +18,21 @@ public class DragEvent {
this.motionEvent = motionEvent; this.motionEvent = motionEvent;
} }
/**
* @return motion event started at start point
*/
@NotNull @NotNull
public MotionEvent getMotionEvent() { public MotionEvent getMotionEvent() {
return motionEvent; return motionEvent;
} }
/**
* @return start point of dragging
*/
@NotNull @NotNull
public Point2d getStartPoint() { public Point2d getStartPoint() {
return startPoint; return startPoint;
} }
} }

View File

@ -1,8 +1,6 @@
package org.solovyev.android.view; package org.solovyev.android.view;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.util.StringUtils;
import org.solovyev.util.math.MathUtils; import org.solovyev.util.math.MathUtils;
import org.solovyev.util.math.Point2d; import org.solovyev.util.math.Point2d;
@ -12,7 +10,7 @@ import android.view.MotionEvent;
public class SimpleOnDragListener implements OnDragListener { public class SimpleOnDragListener implements OnDragListener {
@NotNull @NotNull
private final Point2d axis = new Point2d(0, 1); public static final Point2d axis = new Point2d(0, 1);
private float minDragDist = 20f; private float minDragDist = 20f;
@ -22,11 +20,48 @@ public class SimpleOnDragListener implements OnDragListener {
// vector to register drag event // vector to register drag event
private double maxAngle = 30; private double maxAngle = 30;
@NotNull
private DragProcessor dragProcessor;
public SimpleOnDragListener() {
}
public SimpleOnDragListener(@NotNull DragProcessor dragProcessor) {
this.dragProcessor = dragProcessor;
}
@Override @Override
public boolean onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event) { public boolean onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event) {
boolean result = false;
logDragEvent(dragButton, event); logDragEvent(dragButton, event);
processButtonAction(dragButton, getActionText(dragButton, event)); final Point2d startPoint = event.getStartPoint();
final MotionEvent motionEvent = event.getMotionEvent();
// init end point
final Point2d endPoint = new Point2d(motionEvent.getX(), motionEvent.getY());
float distance = MathUtils.getDistance(startPoint, endPoint);
if (minDragDist < distance && distance < maxDragDist) {
double angle = Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, axis), endPoint));
final DragDirection direction;
if (angle < maxAngle) {
direction = DragDirection.down;
} else if (180 - angle < maxAngle) {
direction = DragDirection.up;
} else {
direction = null;
}
if (direction != null) {
result = dragProcessor.processDragEvent(direction, dragButton, startPoint, motionEvent);
}
}
return result;
} }
@Override @Override
@ -34,60 +69,29 @@ public class SimpleOnDragListener implements OnDragListener {
return true; return true;
} }
/** private void logDragEvent(@NotNull DragButton dragButton, @NotNull DragEvent event) {
* Method creates drag event in case if all conditions are satisfied final Point2d startPoint = event.getStartPoint();
* final MotionEvent motionEvent = event.getMotionEvent();
* @param event final Point2d endPoint = new Point2d(motionEvent.getX(), motionEvent.getY());
* motion event
*
* @return filled drag event object only if drag event is possible, null
* otherwise
*/
@Nullable
protected DragEvent getDragEvent(@NotNull MotionEvent event) {
DragEvent result = null;
if (startPoint != null) { Log.d(String.valueOf(dragButton.getId()), "Start point: " + startPoint + ", End point: " + endPoint);
final Point2d endPoint = new Point2d(event.getX(), event.getY()); Log.d(String.valueOf(dragButton.getId()), "Distance: " + MathUtils.getDistance(startPoint, endPoint));
float distance = MathUtils.getDistance(startPoint, endPoint); Log.d(String.valueOf(dragButton.getId()), "Angle: " + Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, axis), endPoint)));
Log.d(String.valueOf(dragButton.getId()), "Axis: " + axis + " Vector: " + MathUtils.subtract(endPoint, startPoint));
if (minDragDist < distance && distance < maxDragDist) { Log.d(String.valueOf(dragButton.getId()), "Total time: " + (motionEvent.getEventTime() - motionEvent.getDownTime()) + " ms");
double angle = Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, axis), endPoint));
final DragDirection direction;
if (angle < maxAngle) {
direction = DragDirection.down;
} else if (180 - angle < maxAngle) {
direction = DragDirection.up;
} else {
direction = null;
}
if (direction != null) {
if ( direction == DragDirection.up && StringUtils.isEmpty(textUp) ) {
// no action if text is empty
} else if (direction == DragDirection.down && StringUtils.isEmpty(textDown)) {
// no action if text is empty
} else {
result = new DragEvent(direction);
}
}
}
}
return result;
} }
private void logDragEvent(@NotNull DragButton dragButton, @NotNull DragEvent event) { @NotNull
final Point2d startPoint = event.getStartPoint(); public DragProcessor getDragProcessor() {
final MotionEvent motionEvent = event.getMotionEvent(); return dragProcessor;
final Point2d endPoint = new Point2d(motionEvent.getX(), motionEvent.getY()); }
Log.d(String.valueOf(dragButton.getId()), "Start point: " + startPoint + ", End point: " + endPoint); public void setDragProcessor(@NotNull DragProcessor dragProcessor) {
Log.d(String.valueOf(dragButton.getId()), "Distance: " + MathUtils.getDistance(startPoint, endPoint)); this.dragProcessor = dragProcessor;
Log.d(String.valueOf(dragButton.getId()), "Angle: " + Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, axis), endPoint))); }
Log.d(String.valueOf(dragButton.getId()), "Axis: " + axis + " Vector: " + MathUtils.subtract(endPoint, startPoint));
Log.d(String.valueOf(dragButton.getId()), "Total time: " + (motionEvent.getEventTime() - motionEvent.getDownTime()) + " ms"); public interface DragProcessor {
boolean processDragEvent(@NotNull DragDirection dragDirection, @NotNull DragButton dragButton, @NotNull Point2d startPoint2d, @NotNull MotionEvent motionEvent);
} }
} }

View File

@ -2,10 +2,12 @@ package org.solovyev.util.math;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List;
public class MathUtils { public class MathUtils {
public static float getDistance(@NotNull Point2d startPoint, public static float getDistance(@NotNull Point2d startPoint,
@NotNull Point2d endPoint) { @NotNull Point2d endPoint) {
return getNorm(subtract(endPoint, startPoint)); return getNorm(subtract(endPoint, startPoint));
} }
@ -23,7 +25,7 @@ public class MathUtils {
} }
public static float getAngle(@NotNull Point2d startPoint, public static float getAngle(@NotNull Point2d startPoint,
@NotNull Point2d axisEndPoint, @NotNull Point2d endPoint) { @NotNull Point2d axisEndPoint, @NotNull Point2d endPoint) {
final Point2d axisVector = subtract(axisEndPoint, startPoint); final Point2d axisVector = subtract(axisEndPoint, startPoint);
final Point2d vector = subtract(endPoint, startPoint); final Point2d vector = subtract(endPoint, startPoint);
@ -36,4 +38,24 @@ public class MathUtils {
return (float) Math.acos((-a_2 + b_2 + c_2) / (2 * b * c)); return (float) Math.acos((-a_2 + b_2 + c_2) / (2 * b * c));
} }
public static double countMean(@NotNull List<Double> objects) {
double sum = 0d;
for (Double object : objects) {
sum += object;
}
return objects.size() == 0 ? 0d : (sum / objects.size());
}
public static double countStandardDeviation(@NotNull Double mean, @NotNull List<Double> objects) {
double sum = 0d;
for (Double object : objects) {
sum += Math.pow(object - mean, 2);
}
return objects.size() == 0 ? 0d : Math.sqrt(sum / objects.size());
}
} }