closes #12 - implemented tap to estimate bpm
This commit is contained in:
@@ -49,7 +49,7 @@ public class Croller extends View {
|
||||
private float indicatorWidth = 7;
|
||||
|
||||
private String label = "Label";
|
||||
private int labelSize = 40;
|
||||
private int labelSize = 20;
|
||||
private int labelColor = Color.WHITE;
|
||||
|
||||
private int startOffset = 30;
|
||||
@@ -391,7 +391,7 @@ public class Croller extends View {
|
||||
canvas.drawCircle(midx, midy, backCircleRadius, circlePaint);
|
||||
circlePaint.setColor(mainCircleColor);
|
||||
canvas.drawCircle(midx, midy, mainCircleRadius, circlePaint);
|
||||
canvas.drawText(label, midx, midy + (float) (radius * 1.1), textPaint);
|
||||
canvas.drawText(label, midx, midy + (float) (radius * 0.9), textPaint);
|
||||
canvas.drawLine(x1, y1, x2, y2, linePaint);
|
||||
}
|
||||
}
|
||||
@@ -577,11 +577,17 @@ public class Croller extends View {
|
||||
}
|
||||
|
||||
public boolean isMainCircleAnimationRunning(){
|
||||
return mainCircleAnimation.isRunning();
|
||||
if(mainCircleAnimation != null){
|
||||
return mainCircleAnimation.isRunning();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBackCircleAnimationRunning(){
|
||||
return backCircleAnimation.isRunning();
|
||||
if(backCircleAnimation != null){
|
||||
return backCircleAnimation.isRunning();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ValueAnimator backCircleAnimation;
|
||||
|
||||
@@ -13,11 +13,12 @@ import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.sql.Time;
|
||||
import java.util.Vector;
|
||||
|
||||
import de.tonifetzer.conductorswatch.utilities.Utils;
|
||||
|
||||
public class MainActivity extends WearableActivity implements WorkerFragment.OnFragmentInteractionListener{
|
||||
public class MainActivity extends WearableActivity implements WorkerFragment.OnFragmentInteractionListener, TapBpm.OnTapBpmListener{
|
||||
|
||||
// member
|
||||
private TextView mTextView;
|
||||
@@ -34,7 +35,11 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
||||
private int mMetronomBpm;
|
||||
|
||||
// tapping
|
||||
private int mReceivedTabs;
|
||||
private Thread mTapBpmThread;
|
||||
private TapBpm mTapBpm;
|
||||
private boolean mTapRecognized = false;
|
||||
private int mTapBpmEstimation;
|
||||
private Vibrator mVibrator;
|
||||
|
||||
//parameter for long press to start the worker
|
||||
private Point mPreviousMovePoint;
|
||||
@@ -161,9 +166,36 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
||||
|
||||
public boolean onTapForBpm(MotionEvent ev){
|
||||
|
||||
Point currentPoint = new Point((int)ev.getX(), (int)ev.getY());
|
||||
|
||||
//only works within the maincircle of the scroller
|
||||
float distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, mDisplayCenter.x, mDisplayCenter.y);
|
||||
if ((distancePointToMiddle > mCroller.getMainCircleRadius())){
|
||||
|
||||
return true;
|
||||
mCroller.setProgress(mCroller.getProgress());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ev.getAction() == MotionEvent.ACTION_DOWN){
|
||||
|
||||
if(!mTapRecognized){
|
||||
|
||||
mTapBpm.addTimestamp(System.currentTimeMillis());
|
||||
mTapRecognized = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(ev.getAction() == MotionEvent.ACTION_UP) {
|
||||
|
||||
if(!mTapBpmThread.isAlive()){
|
||||
mTapBpmThread.start();
|
||||
mCroller.setLabel("Tippe weiter");
|
||||
}
|
||||
mTapRecognized = false;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,6 +209,11 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
||||
|
||||
mModeRecord = false;
|
||||
|
||||
mTapBpm = new TapBpm();
|
||||
mTapBpm.add(this);
|
||||
mTapBpmThread = new Thread(mTapBpm, "tapThread");
|
||||
mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
||||
|
||||
mTextView = (TextView) findViewById(R.id.bpmText);
|
||||
|
||||
// circular progress bar
|
||||
@@ -185,7 +222,6 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
||||
@Override
|
||||
public void onProgressChanged(int progress) {
|
||||
// use the progress
|
||||
//Log.d("Progress: ", String.valueOf(progress));
|
||||
mTextView.setText(String.valueOf(progress));
|
||||
}
|
||||
});
|
||||
@@ -217,7 +253,11 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
||||
else {
|
||||
|
||||
boolean changeColor = onColorChanging(ev, Color.parseColor("#158b69"));
|
||||
return onLongPressCustomized(ev) || super.dispatchTouchEvent(ev);
|
||||
boolean superTouch = super.dispatchTouchEvent(ev);
|
||||
boolean longPress = onLongPressCustomized(ev);
|
||||
boolean tapForBpm = onTapForBpm(ev);
|
||||
|
||||
return superTouch || longPress;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -232,5 +272,40 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF
|
||||
Log.d("FragmentListener", "Received bpmList");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewEstimation(int bpm) {
|
||||
mTapBpmEstimation = bpm;
|
||||
|
||||
synchronized (this) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(mTapBpmEstimation > 0){
|
||||
mCroller.setProgress(mTapBpmEstimation);
|
||||
mCroller.setLabel("Fertig");
|
||||
mVibrator.vibrate(10);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished() {
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCroller.setLabel("");
|
||||
}
|
||||
});
|
||||
|
||||
mTapBpm.clearTimestamps();
|
||||
mTapBpmThread.interrupt();
|
||||
try {
|
||||
mTapBpmThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package de.tonifetzer.conductorswatch;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* Created by toni on 20/11/17.
|
||||
*/
|
||||
|
||||
public class TapBpm implements Runnable {
|
||||
|
||||
private Vector<Long> mReceivedTabs = new Vector<Long>();
|
||||
private int mBpmTapped;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int breakCounter = 2000;
|
||||
mBpmTapped = 0;
|
||||
int calcNewBpmCounter = 3;
|
||||
|
||||
do{
|
||||
if(mBpmTapped > 0){
|
||||
breakCounter = 2 * (60000 / mBpmTapped);
|
||||
}
|
||||
|
||||
if (mReceivedTabs.size() > calcNewBpmCounter) {
|
||||
|
||||
Long sumDifferenceMs = 0l;
|
||||
for (int i = 0; i < mReceivedTabs.size() -1; ++i) {
|
||||
sumDifferenceMs += mReceivedTabs.get(i + 1)- mReceivedTabs.get(i);
|
||||
}
|
||||
mBpmTapped = (int) (60000 / (sumDifferenceMs / (mReceivedTabs.size() - 1)));
|
||||
|
||||
for (TapBpm.OnTapBpmListener listener:listeners) {
|
||||
listener.onNewEstimation(mBpmTapped);
|
||||
}
|
||||
|
||||
//only update everytime a new timestamp arrives
|
||||
++calcNewBpmCounter;
|
||||
}
|
||||
}while(System.currentTimeMillis() - mReceivedTabs.lastElement() < breakCounter);
|
||||
|
||||
|
||||
for (TapBpm.OnTapBpmListener listener:listeners) {
|
||||
listener.onFinished();
|
||||
}
|
||||
}
|
||||
|
||||
public void addTimestamp(Long ts){
|
||||
mReceivedTabs.add(ts);
|
||||
}
|
||||
|
||||
public void clearTimestamps(){
|
||||
mReceivedTabs.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for callback calculated bpm
|
||||
*/
|
||||
public interface OnTapBpmListener {
|
||||
void onFinished();
|
||||
void onNewEstimation(int bpm);
|
||||
}
|
||||
|
||||
private List<TapBpm.OnTapBpmListener> listeners = new CopyOnWriteArrayList<TapBpm.OnTapBpmListener>();
|
||||
public void add(TapBpm.OnTapBpmListener listener){listeners.add(listener);}
|
||||
public void remove(TapBpm.OnTapBpmListener listener){listeners.remove(listener);}
|
||||
}
|
||||
@@ -2,16 +2,12 @@ package de.tonifetzer.conductorswatch;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
import android.os.Bundle;
|
||||
import android.app.Fragment;
|
||||
import android.os.Vibrator;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
import java.util.Vector;
|
||||
|
||||
30
android/ConductorsWatch/app/src/main/res/values/attrs.xml
Normal file
30
android/ConductorsWatch/app/src/main/res/values/attrs.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="Croller">
|
||||
<attr name="progress" format="integer" />
|
||||
<attr name="label" format="string" />
|
||||
<attr name="back_circle_color" format="color" />
|
||||
<attr name="main_circle_color" format="color" />
|
||||
<attr name="indicator_color" format="color" />
|
||||
<attr name="progress_primary_color" format="color" />
|
||||
<attr name="progress_secondary_color" format="color" />
|
||||
<attr name="label_size" format="integer" />
|
||||
<attr name="label_color" format="color" />
|
||||
<attr name="indicator_width" format="float" />
|
||||
<attr name="is_continuous" format="boolean" />
|
||||
<attr name="progress_primary_circle_size" format="float" />
|
||||
<attr name="progress_secondary_circle_size" format="float" />
|
||||
<attr name="progress_primary_stroke_width" format="float" />
|
||||
<attr name="progress_secondary_stroke_width" format="float" />
|
||||
<attr name="sweep_angle" format="integer" />
|
||||
<attr name="start_offset" format="integer" />
|
||||
<attr name="max" format="integer" />
|
||||
<attr name="min" format="integer" />
|
||||
<attr name="main_circle_radius" format="float" />
|
||||
<attr name="back_circle_radius" format="float" />
|
||||
<attr name="progress_radius" format="float" />
|
||||
<attr name="touch_circle_radius_max" format="float" />
|
||||
<attr name="touch_circle_radius_min" format="float" />
|
||||
<attr name="anticlockwise" format="boolean" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user