How to Animate Text from a Shake Event - java

I currently have an app that allows the user to shake the phone and different texts appear from an array. However, the text keeps displaying too fast, and if the user keeps shaking the phone, the text keeps changing. How do i do the following:
1) Animate the text so after the phone is shaken, the text appears slowly as a fade?
How do I implement a delay on the shake so that the user has a wait a few seconds before shaking the phone?
I have already implemented this for a button that is clicked, however nothing seems to work with Sensor Manager.
protected final SensorEventListener sensorListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
float x = sensorEvent.values[0];
float y = sensorEvent.values[1];
float z = sensorEvent.values[2];
acelLast = acelVal;
acelVal = (float) Math.sqrt((double) (x*x + y*y + z*z));
float delta = acelVal - acelLast;
shake = shake * 0.9f + delta;
if (shake > 12) {
int randomNum = new Random().nextInt(answersArray.length);
ball_text.setText(answersArray[randomNum]);
ball_text.setVisibility(View.VISIBLE);
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
// Sensor Section //

You'll need to animate your textview's alpha value change.
You'll need to keep track of the last time the user shaked and use that for checking.
Something along the following lines should work,
long previousTime = 0;
protected final SensorEventListener sensorListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
float x = sensorEvent.values[0];
float y = sensorEvent.values[1];
float z = sensorEvent.values[2];
acelLast = acelVal;
acelVal = (float) Math.sqrt((double) (x*x + y*y + z*z));
float delta = acelVal - acelLast;
shake = shake * 0.9f + delta;
if (shake > 12) {
//Fade in text if difference between previous and current time is > 2 seconds
if (System.currentTimeMillis() - previousTime > 2000) {
previousTime = System.currentTimeMillis();
//Use AlphaAnimation
Animation fadeInAnimation = new AlphaAnimation(0, 1);
fadeInAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
int randomNum = new Random().nextInt(answersArray.length);
ball_text.setText(answersArray[randomNum]);
ball_text.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {}
#Override
public void onAnimationRepeat(Animation animation) {}
});
fadeInAnimation.setInterpolator(new DecelerateInterpolator());
fadeInAnimation.setDuration(1000);
ball_text.startAnimation(fadeInAnimation);
/*
//This should work, but it doesn't, I'll prob tinker with it on some weekend, I'll update the answer if I figure out the issue
ball_text.animate()
.withStartAction(new Runnable() {
#Override
public void run() {
int randomNum = new Random().nextInt(answersArray.length);
ball_text.setText(answersArray[randomNum]);
ball_text.setAlpha(0f);
ball_text.setVisibility(View.VISIBLE);
}
})
.alpha(1f)
//Fade in over a duration of 1 second
.setDuration(1000)
.start()
*/
} else {
//If it's less than 2 seconds since last shake, inform user to wait
//For eg,
Toast.makeText(context, "Wait mate", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};

Related

How to calculate ProgressBar percentage for daily drink water

I made an app about android water drinking monitor. But it does the wrong calculation as a percentage. What do you think I might have done wrong.
(When the progress bar is 100 at 100, the daily water calculation is wrong)
waterml = sharedPreferences.getInt(WATER_ML, 0);
waterdata = sharedPreferences.getInt(WATER_DATA, 0);
int dailywater = 2838; // example
ml100.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//scale 100 ml
int percent = 100 * 100 / dailywater;
ProgressBarAnimation anim = new ProgressBarAnimation(circlebar, waterdata, (waterdata + percent));
anim.setDuration(300);
circlebar.startAnimation(anim);
dailywater.setText((waterml + 100) + " / " + dailywater + " ml");
editor = sharedPreferences.edit();
editor.putInt(WATER_DATA, (waterdata + percent));
editor.putInt(WATER_ML, (waterml + 100));
editor.apply();
}
});
////
public static class ProgressBarAnimation extends Animation {
private CircleProgressBar progressBar;
private float from;
private float to;
ProgressBarAnimation(CircleProgressBar progressBar, float from, float to) {
super();
this.progressBar = progressBar;
this.from = from;
this.to = to;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
float value = from + (to - from) * interpolatedTime;
progressBar.setProgress((int) value);
}
}
It seems to me like your code, namely editor.apply(); is working as follows:
you are trying to save the progress and it occurs that sometimes it is called multiple times in a row. According to documentation if you are sending several apply() or commit() commands only the last one will be executed. Therefore, some clicks might not be processed.
I suggest you simply changing your variable for progress and saving it later:
waterml = sharedPreferences.getInt(WATER_ML, 0);
waterdata = sharedPreferences.getInt(WATER_DATA, 0);
int dailywater = 2838; // example
ml100.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//scale 100 ml
int percent = 100 * 100 / dailywater;
ProgressBarAnimation anim = new ProgressBarAnimation(circlebar, waterdata, (waterdata + percent));
anim.setDuration(300);
circlebar.startAnimation(anim);
dailywater.setText((waterml + 100) + " / " + dailywater + " ml");
waterdata += percent;
waterml += 100;
}
});
and then in your onPause() function you simply save them:
public void onPause() {
editor = sharedPreferences.edit();
editor.putInt(WATER_DATA, waterdata);
editor.putInt(WATER_ML, waterml);
editor.apply();
}
If you want your percent not to be rounded, you could change putInt to putFloat and getInt to getFloat

Android Fall Detection Issue

I'm trying to implement a simple fall detection algorithm using android's accelerometer.
The current acceleration of the phone is stored in mAccel and if a sudden shake is detected Timer t begins. Inside the Timer are two CountDownTimers.
The firstTimer is used to register a "fall" if the user hasn't moved in the last 5 seconds and the secondTimer to confirm that fall if the user hasn't pressed a button (not implemented yet).
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity = event.values.clone();
float x = mGravity[0];
float y = mGravity[1];
float z = mGravity[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float) Math.sqrt(x * x + y * y + z * z);
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta;
mAccel = abs(mAccel);
textView.setText("a:"+mAccel);
if (abs(mAccel) > 5.0f) { // Shake detection
t();
}
}
}
public void t () {
firstTimer = new CountDownTimer(5000, 1000) { //fall registration timer
#Override
public void onTick(long millisUntilFinished) {
//if there is movement before 5 seconds pass cancel the timer
if (abs(mAccel) > 2.0f) {
firstTimer.cancel();
firstTimer = null;
}
}
#Override
public void onFinish() {
toast.show();
secondTimer = new CountDownTimer(30*1000, 1000) { //fall confirmation timer
#Override
public void onTick(long millisUntilFinished) {
textView2.setText("" + millisUntilFinished / 1000);
}
#Override
public void onFinish() {
Toast toast = Toast.makeText(getApplicationContext(),
"Fall Registered!", Toast.LENGTH_LONG);
toast.show();
}
}.start();
}
}.start();
}
The main issue is that most timesfirstTimer is accessed, it gets cancelled due to the mAccel being over the 2.0 threshold, while it is decelerating.
I tried to use Timer.schedule() to delay the activation of firstTimer until after the acceleration value has "rested" but it won't work with it.
I created a new Timer object mTimer and this seems to work on every case.
CountDownTimer firstTimer = new CountDownTimer(5000, 1000) { //fall registration timer
#Override
public void onTick(long millisUntilFinished) {
//if there is movement before 5 seconds pass cancel the timer
if (abs(mAccel) > 2.0f) {
Toast toast = Toast.makeText(getApplicationContext(),
"Fall not Detected", Toast.LENGTH_SHORT);
toast.show();
firstTimer.cancel();
}
}
#Override
public void onFinish() {
Toast toast = Toast.makeText(getApplicationContext(),
"Fall Detected!", Toast.LENGTH_SHORT);
toast.show();
secondTimer.start();
}
};
CountDownTimer secondTimer = new CountDownTimer(30*1000, 1000) {
//fall confirmation timer
#Override
public void onTick(long millisUntilFinished) {
textView2.setText("" + millisUntilFinished / 1000);
}
#Override
public void onFinish() {
Toast toast = Toast.makeText(getApplicationContext(),
"Fall Registered!", Toast.LENGTH_LONG);
toast.show();
}
};
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mGravity = event.values.clone();
float x = mGravity[0];
float y = mGravity[1];
float z = mGravity[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float) Math.sqrt(x * x + y * y + z * z);
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta;
mAccel = abs(mAccel);
textView.setText("a:"+mAccel);
if (abs(mAccel) > 5.0f) { // Shake detection
mTimer.schedule(new TimerTask() {
//start after 2 second delay to make acceleration values "rest"
#Override
public void run() {
firstTimer.start();
}
}, 2000);
}
}
}

shared preference editor mixing up values

in my text to speech style app I can set the speed and pitch of the voice, and also 2 variables for ultrasound pitch settings. If I set the speed and pitch and exit the settings menu everything is fine, The problem is that if I press the finish button and the frequency analyzer runs and sets the ultrasound variables the variables get saved in the preference editor in the wrong spot, causing the speed and pitch to be set at the ultrasound values, I have been trying for 2 days to fix it but nothing works, below is the relevant code, if you need more please ask, can anyone see what I'm doing wrong?
EDIT: here is an apk showing the problem, go to settings menu (from toolbar upper right) set the speed and pitch, press finish, close app, open app, go to settings and you will see the ridiculous values set as speed and pitch
Canine Remote apk
Relevant initialized variables at start of class:
public SharedPreferences appPreferences;
boolean settingUp=false;
int result = 0;
int remote = 0;
int settingLanguage=0;
private float progress = (float) 1.0;
private float progress2 = (float) 1.0;
private static final String LSTYLE = "usa";//language
private static final String MYPITCH = "1.0";//normal use voice pitch
private static final String MYSPEED = "1.0";//normal use voice speed
private static final String ULTRADOG = "1.0";//22000 +/- user pitch khz
private static final String ULTRACAT = "1.0";//48000 +/- user pitch khz
private static final String HUMANDOGCAT = "0";//human=0, dog=1, cat=2
private static final String REMOTE = "0";//speak through device=0, speak
//through remote bluetooth speaker=1
private TextView edit;
private TextView edit2;
private Button edit3;
private Button edit4;
private Button edit5;
private Button edit6;
private TextView edit7;
private ImageButton edit8;
private Button edit9;
private CheckBox ckultra;
private CheckBox cklocal;
private CheckBox ckultra2;
private SeekBar cpitch;
private SeekBar cspeed;
AudioRecord mAudioRecord;
int freq = 11025;
int Nb;
int N;
int running=0;
double FreqMin = 0;
double FreqMax = 2300;
int muestras = 1000;
double PI2n = 2 * Math.PI/muestras;
double FreqMuestras=freq/muestras;
int indMin = (int) (FreqMin/FreqMuestras);
int indMax = (int) (FreqMax/FreqMuestras);
double newFrequency = 170;
double freakMin=170;
double freakMax=170;
double mean=170;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_canine_start);
appPreferences = PreferenceManager.getDefaultSharedPreferences(this);
This button sets the pitch in the preference editor
edit3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Globals g = (Globals) getApplication();
SharedPreferences.Editor editor = appPreferences.edit();
float pitch = g.getData2();
if (pitch < 0.1) pitch = (float) 0.1;
editor.putFloat(MYPITCH, pitch);
editor.commit();
tts.setPitch(pitch);
}
});
This button sets the speed in the preference editor, also I've included the slider bars and check boxes codes here if you need to see them
edit4.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Globals g = (Globals) getApplication();
SharedPreferences.Editor editor2 = appPreferences.edit();
float speed=g.getData3();
if (speed < 0.1) speed = (float) 0.1;
editor2.putFloat(MYSPEED, speed);
editor2.commit();
tts.setSpeechRate(speed);
}
});
//slider bars to get pitch and speed
cpitch.setProgress(1);
edit.setText("Adjust voice Pitch: " + cpitch.getProgress());
cpitch.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
Globals g = (Globals) getApplication();
#Override
public void onProgressChanged(SeekBar cpitch, int progresValue, boolean fromUser) {
progress = (float) (progresValue * 0.1);
edit.setText("Adjust voice pitch: " + progress);
}
#Override
public void onStartTrackingTouch(SeekBar cpitch) {
}
#Override
public void onStopTrackingTouch(SeekBar cpitch) {
edit.setText("Adjust voice pitch: " + progress);
g.setData2(progress);
}
});
cspeed.setProgress(1);
edit2.setText("Adjust voice speed: " + cspeed.getProgress());
cspeed.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
Globals g = (Globals) getApplication();
#Override
public void onProgressChanged(SeekBar cspeed, int progresValue2, boolean fromUser2) {
progress2 = (float) (progresValue2 * 0.1);
edit2.setText("Adjust voice speed: " + progress2);
}
#Override
public void onStartTrackingTouch(SeekBar cspeed) {
}
#Override
public void onStopTrackingTouch(SeekBar cspeed) {
edit2.setText("Adjust voice speed: " + progress2);
g.setData3(progress2);
}
});
}
//check boxes
class clicker implements CheckBox.OnCheckedChangeListener {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
SharedPreferences.Editor editor5 = appPreferences.edit();
if (isChecked) {
if (buttonView == ckultra) {
editor5.putInt(HUMANDOGCAT, 1).commit();
ckultra2.setChecked(false);
}
if (buttonView == ckultra2) {
editor5.putInt(HUMANDOGCAT, 2).commit();
ckultra.setChecked(false);
}
if (buttonView == cklocal) {
editor5.putInt(REMOTE, 1).commit();
}
}
if (!isChecked) {
if (buttonView == ckultra) {
editor5.putInt(HUMANDOGCAT, 0).commit();
}
if (buttonView == ckultra2) {
editor5.putInt(HUMANDOGCAT, 0).commit();
}
if (buttonView == cklocal) {
editor5.putInt(REMOTE, 0).commit();
}
}
}
}
This button is the start of the code causing the error
edit6.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
edit7.setVisibility(View.VISIBLE);
edit8.setVisibility(View.VISIBLE);
edit9.setVisibility(View.VISIBLE);
edit.setVisibility(View.GONE);
edit2.setVisibility(View.GONE);
edit3.setVisibility(View.GONE);
edit4.setVisibility(View.GONE);
edit5.setVisibility(View.GONE);
edit6.setVisibility(View.GONE);
cpitch.setVisibility(View.GONE);
cspeed.setVisibility(View.GONE);
ckultra.setVisibility(View.GONE);
ckultra2.setVisibility(View.GONE);
cklocal.setVisibility(View.GONE);
speakIT("Completed.");
Spectrometer_Start();
}
});
//analyze pitch to set ultrasound variables
public void Spectrometer_Start() {
try {
Nb = AudioRecord.getMinBufferSize(freq, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT) * 4;
N = Nb * Byte.SIZE / Short.SIZE;
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, freq, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, Nb);
mAudioRecord.startRecording();
running=1;
analizer();
} catch (IllegalArgumentException i) {
}
}
This method saves the ultrasound settings in the wrong place in the preference editor
public void analizer() {
int a=10;
while(tts.isSpeaking())
{
a-=1;
if(a==0)
{
short[] data= new short[muestras];
try {
mAudioRecord.read(data, 0, muestras-1);
Dft(data);
} catch (Exception e) {
e.printStackTrace();
}
a=10;
}
}
mAudioRecord.stop();
mAudioRecord.release();
Globals g = (Globals) getApplication();
running=0;
mean=((freakMax-freakMin)*0.5)+freakMin;
float calcDog = (float) (22000 / mean);
float calcCat = (float) (48000 / mean);
g.setData4(calcDog);
g.setData5(calcCat);
SharedPreferences.Editor editor7 = appPreferences.edit();
editor7.putFloat(ULTRADOG, calcDog);
editor7.putFloat(ULTRACAT, calcCat);
editor7.commit();
}
public void Dft(short[] inreal) {
for (int k = indMin; k < indMax; k++)
{
float sumreal = 0;
float sumimag = 0;
float PI2kn= (float) (PI2n * k);
for (int t = 0; t < muestras; t++) {
double angle = t*PI2kn;
sumreal += inreal[t] * Math.cos(angle);
sumimag += inreal[t] * Math.sin(angle);
}
newFrequency = (Math.sqrt(sumreal * sumreal + sumimag * sumimag));
if (newFrequency < freakMin && newFrequency >= 85) {
freakMin = newFrequency;
}
if (newFrequency > freakMax && newFrequency <= 255) {
freakMax = newFrequency;
}
}
}
This button starts the speech entered, and receives the wrong values from the preference editor
edit9.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String sendComands= edit7.getText().toString();
if (!sendComands.equals("") && settingLanguage == 0){
float NPITCH = appPreferences.getFloat(MYPITCH, (float) 1.0);
float NSPEED = appPreferences.getFloat(MYSPEED, (float) 1.0);
float UDOG = appPreferences.getFloat(ULTRADOG, (float) 1.0);
float UCAT = appPreferences.getFloat(ULTRACAT, (float) 1.0);
int HDC = appPreferences.getInt(HUMANDOGCAT, 0);
switch (HDC) {
case 0:
tts.setPitch(NPITCH);
break;
case 1:
tts.setPitch(UDOG);
break;
case 2:
tts.setPitch(UCAT);
break;
}
tts.setSpeechRate(NSPEED);
speakIT(sendComands);
edit7.setHint("Enter text to send");
settingUp=false;
}
if (settingLanguage == 1) {
countryC(sendComands);
settingLanguage=0;
edit7.setHint("Enter text to send");
edit9.setText("Send");
edit7.setVisibility(View.GONE);
edit9.setVisibility(View.GONE);
}
}
});
My settings menu in the toolbar with comment so you know which objects do what
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.canine_start, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Globals g = (Globals) getApplication();
int id = item.getItemId();
if (id == R.id.action_settings) {
edit.setVisibility(View.VISIBLE);//pitch slider text
edit2.setVisibility(View.VISIBLE);//speed slider text
edit3.setVisibility(View.VISIBLE);//button - set pitch
edit4.setVisibility(View.VISIBLE);//button - set speed
edit5.setVisibility(View.VISIBLE);//button - test speak
edit6.setVisibility(View.VISIBLE);//button - finished with settings
edit7.setVisibility(View.GONE);//edit text - text to speech
edit8.setVisibility(View.GONE);//image button - speech recognition start
edit9.setVisibility(View.GONE);//button - speak edit7 text
cpitch.setVisibility(View.VISIBLE);//slider - adjust voice pitch
cspeed.setVisibility(View.VISIBLE);//slider - adjust voice speed
ckultra.setVisibility(View.VISIBLE);//checkbox - ultrasound dog on/off
ckultra2.setVisibility(View.VISIBLE);//checkbox - ultrasound cat on/off
cklocal.setVisibility(View.VISIBLE);//checkbox - send to bluetooth/local device
settingUp=true;
return true;
}
Your are using invalid keys to stores your values in sharedPreferences:
These values are used as keys:
private static final String MYPITCH = "1.0";
private static final String MYSPEED = "1.0";
private static final String ULTRADOG = "1.0";
private static final String ULTRACAT = "1.0";
Here to store values
editor.putFloat(MYPITCH, pitch);
editor2.putFloat(MYSPEED, speed);
editor7.putFloat(ULTRADOG, calcDog);
editor7.putFloat(ULTRACAT, calcCat);
And here to get values
float NPITCH = appPreferences.getFloat(MYPITCH, (float) 1.0);
float NSPEED = appPreferences.getFloat(MYSPEED, (float) 1.0);
float UDOG = appPreferences.getFloat(ULTRADOG, (float) 1.0);
float UCAT = appPreferences.getFloat(ULTRACAT, (float) 1.0);
You should instead use unique and meaningful keys:
private static final String MYPITCH = "my_pitch";
private static final String MYSPEED = "my_speed";
private static final String ULTRADOG = "ultra_dog";
private static final String ULTRACAT = "ultra_cat";

Followed tutorial on creating a shake listener, having trouble using it

I'm simply trying to learn android using baby-steps. I've followed a tutorial on how to implement a "shake listener" from this tutorial
This is it:
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.FloatMath;
public class ShakeListener implements SensorEventListener {
/*
* The gForce that is necessary to register as shake.
* Must be greater than 1G (one earth gravity unit).
* You can install "G-Force", by Blake La Pierre
* from the Google Play Store and run it to see how
* many G's it takes to register a shake
*/
private static final float SHAKE_THRESHOLD_GRAVITY = 2.7F;
private static final int SHAKE_SLOP_TIME_MS = 500;
private static final int SHAKE_COUNT_RESET_TIME_MS = 3000;
private OnShakeListener mListener;
private long mShakeTimestamp;
private int mShakeCount;
public void setOnShakeListener(OnShakeListener listener) {
this.mListener = listener;
}
public interface OnShakeListener {
public void onShake(int count);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// ignore
}
#Override
public void onSensorChanged(SensorEvent event) {
if (mListener != null) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
float gX = x / SensorManager.GRAVITY_EARTH;
float gY = y / SensorManager.GRAVITY_EARTH;
float gZ = z / SensorManager.GRAVITY_EARTH;
// gForce will be close to 1 when there is no movement.
float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);
if (gForce > SHAKE_THRESHOLD_GRAVITY) {
final long now = System.currentTimeMillis();
// ignore shake events too close to each other (500ms)
if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now) {
return;
}
// reset the shake count after 3 seconds of no shakes
if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
mShakeCount = 0;
}
mShakeTimestamp = now;
mShakeCount++;
mListener.onShake(mShakeCount);
}
}
}
}
I read jokes from a folder and I'd like to display a new one every time I shake the phone. I have no idea how to call the shake listener.
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private ShakeListener mShakeListener;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
TextView textView = new TextView(this);
textView.setTextSize(16);
String[] test = processData(readText(message));
textView.setText(test[0]); // later will use random
//________________________________________________
// THIS IS THE PART I HAVE NO IDEA HOW TO IMPLEMENT.
while (true) {
if (shake)
textView.setText(test[RandomNumber]);
}
//________________________________________________
setContentView(textView);
}
I think this is what I should use, but frankly I don't understand what's going on:
// ShakeListener initialization
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mShakeListener = new ShakeListener();
mShakeListener.setOnShakeListener(new OnShakeListener() {
#Override
public void onShake(int count) {
/*
* The following method, "handleShakeEvent(count):" is a stub //
* method you would use to setup whatever you want done once the
* device has been shook.
*/
handleShakeEvent(count);
}
});
You don't call Listeners. They call you.
Move:
while (true) {
if (shake)
textView.setText(test[RandomNumber]); // this line
}
to:
#Override
public void onShake(int count) {
/*
* HERE
*/
handleShakeEvent(count);
}
Should achieve what you're aiming for.

How to detect shake event [duplicate]

How can I detect a shake event with android? How can I detect the shake direction?
I want to change the image in an imageview when shaking occurs.
From the code point of view, you need to implement the SensorListener:
public class ShakeActivity extends Activity implements SensorListener
You will need to acquire a SensorManager:
sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
And register this sensor with desired flags:
sensorMgr.registerListener(this,
SensorManager.SENSOR_ACCELEROMETER,
SensorManager.SENSOR_DELAY_GAME);
In your onSensorChange() method, you determine whether it’s a shake or not:
public void onSensorChanged(int sensor, float[] values) {
if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
long curTime = System.currentTimeMillis();
// only allow one update every 100ms.
if ((curTime - lastUpdate) > 100) {
long diffTime = (curTime - lastUpdate);
lastUpdate = curTime;
x = values[SensorManager.DATA_X];
y = values[SensorManager.DATA_Y];
z = values[SensorManager.DATA_Z];
float speed = Math.abs(x+y+z - last_x - last_y - last_z) / diffTime * 10000;
if (speed > SHAKE_THRESHOLD) {
Log.d("sensor", "shake detected w/ speed: " + speed);
Toast.makeText(this, "shake detected w/ speed: " + speed, Toast.LENGTH_SHORT).show();
}
last_x = x;
last_y = y;
last_z = z;
}
}
}
The shake threshold is defined as:
private static final int SHAKE_THRESHOLD = 800;
There are some other methods too, to detect shake motion. look at this link.(If that link does not work or link is dead, look at this web archive.).
Have a look at this example for android shake detect listener.
Note: SensorListener is deprecated. we can use SensorEventListener instead. Here is a quick example using SensorEventListener.
Thanks.
Google helps a lot.
/* The following code was written by Matthew Wiggins
* and is released under the APACHE 2.0 license
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.hlidskialf.android.hardware;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.content.Context;
import java.lang.UnsupportedOperationException;
public class ShakeListener implements SensorListener
{
private static final int FORCE_THRESHOLD = 350;
private static final int TIME_THRESHOLD = 100;
private static final int SHAKE_TIMEOUT = 500;
private static final int SHAKE_DURATION = 1000;
private static final int SHAKE_COUNT = 3;
private SensorManager mSensorMgr;
private float mLastX=-1.0f, mLastY=-1.0f, mLastZ=-1.0f;
private long mLastTime;
private OnShakeListener mShakeListener;
private Context mContext;
private int mShakeCount = 0;
private long mLastShake;
private long mLastForce;
public interface OnShakeListener
{
public void onShake();
}
public ShakeListener(Context context)
{
mContext = context;
resume();
}
public void setOnShakeListener(OnShakeListener listener)
{
mShakeListener = listener;
}
public void resume() {
mSensorMgr = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
if (mSensorMgr == null) {
throw new UnsupportedOperationException("Sensors not supported");
}
boolean supported = mSensorMgr.registerListener(this, SensorManager.SENSOR_ACCELEROMETER, SensorManager.SENSOR_DELAY_GAME);
if (!supported) {
mSensorMgr.unregisterListener(this, SensorManager.SENSOR_ACCELEROMETER);
throw new UnsupportedOperationException("Accelerometer not supported");
}
}
public void pause() {
if (mSensorMgr != null) {
mSensorMgr.unregisterListener(this, SensorManager.SENSOR_ACCELEROMETER);
mSensorMgr = null;
}
}
public void onAccuracyChanged(int sensor, int accuracy) { }
public void onSensorChanged(int sensor, float[] values)
{
if (sensor != SensorManager.SENSOR_ACCELEROMETER) return;
long now = System.currentTimeMillis();
if ((now - mLastForce) > SHAKE_TIMEOUT) {
mShakeCount = 0;
}
if ((now - mLastTime) > TIME_THRESHOLD) {
long diff = now - mLastTime;
float speed = Math.abs(values[SensorManager.DATA_X] + values[SensorManager.DATA_Y] + values[SensorManager.DATA_Z] - mLastX - mLastY - mLastZ) / diff * 10000;
if (speed > FORCE_THRESHOLD) {
if ((++mShakeCount >= SHAKE_COUNT) && (now - mLastShake > SHAKE_DURATION)) {
mLastShake = now;
mShakeCount = 0;
if (mShakeListener != null) {
mShakeListener.onShake();
}
}
mLastForce = now;
}
mLastTime = now;
mLastX = values[SensorManager.DATA_X];
mLastY = values[SensorManager.DATA_Y];
mLastZ = values[SensorManager.DATA_Z];
}
}
}
You can also take a look on library Seismic
public class Demo extends Activity implements ShakeDetector.Listener {
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
ShakeDetector sd = new ShakeDetector(this);
// A non-zero delay is required for Android 12 and up (https://github.com/square/seismic/issues/24)
int sensorDelay = SensorManager.SENSOR_DELAY_GAME
sd.start(sensorManager, sensorDelay);
TextView tv = new TextView(this);
tv.setGravity(CENTER);
tv.setText("Shake me, bro!");
setContentView(tv, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
#Override public void hearShake() {
Toast.makeText(this, "Don't shake me, bro!", Toast.LENGTH_SHORT).show();
}
}
There are a lot of solutions to this question already, but I wanted to post one that:
Doesn't use a library depricated in API 3
Calculates the magnitude of the acceleration correctly
Correctly applies a timeout between shake events
Here is such a solution:
// variables for shake detection
private static final float SHAKE_THRESHOLD = 3.25f; // m/S**2
private static final int MIN_TIME_BETWEEN_SHAKES_MILLISECS = 1000;
private long mLastShakeTime;
private SensorManager mSensorMgr;
To initialize the timer:
// Get a sensor manager to listen for shakes
mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
// Listen for shakes
Sensor accelerometer = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (accelerometer != null) {
mSensorMgr.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
SensorEventListener methods to override:
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
long curTime = System.currentTimeMillis();
if ((curTime - mLastShakeTime) > MIN_TIME_BETWEEN_SHAKES_MILLISECS) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
double acceleration = Math.sqrt(Math.pow(x, 2) +
Math.pow(y, 2) +
Math.pow(z, 2)) - SensorManager.GRAVITY_EARTH;
Log.d(APP_NAME, "Acceleration is " + acceleration + "m/s^2");
if (acceleration > SHAKE_THRESHOLD) {
mLastShakeTime = curTime;
Log.d(APP_NAME, "Shake, Rattle, and Roll");
}
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Ignore
}
When you are all done
// Stop listening for shakes
mSensorMgr.unregisterListener(this);
Since SensorListener is deprecated so use the following code:
/* put this into your activity class */
private SensorManager mSensorManager;
private float mAccel; // acceleration apart from gravity
private float mAccelCurrent; // current acceleration including gravity
private float mAccelLast; // last acceleration including gravity
private final SensorEventListener mSensorListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent se) {
float x = se.values[0];
float y = se.values[1];
float z = se.values[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float) Math.sqrt((double) (x*x + y*y + z*z));
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta; // perform low-cut filter
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
#Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
mSensorManager.unregisterListener(mSensorListener);
super.onPause();
}
Then:
/* do this in onCreate */
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(mSensorListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
mAccel = 0.00f;
mAccelCurrent = SensorManager.GRAVITY_EARTH;
mAccelLast = SensorManager.GRAVITY_EARTH;
The question with full details could be found here:
Android: I want to shake it
This is for Kotlin and use SensorEventListener
Create new class ShakeDetector
class ShakeDetector : SensorEventListener {
private var mListener: OnShakeListener? = null
private var mShakeTimestamp: Long = 0
private var mShakeCount = 0
fun setOnShakeListener(listener: OnShakeListener?) {
mListener = listener
}
interface OnShakeListener {
fun onShake(count: Int)
}
override fun onAccuracyChanged(
sensor: Sensor,
accuracy: Int
) { // ignore
}
override fun onSensorChanged(event: SensorEvent) {
if (mListener != null) {
val x = event.values[0]
val y = event.values[1]
val z = event.values[2]
val gX = x / SensorManager.GRAVITY_EARTH
val gY = y / SensorManager.GRAVITY_EARTH
val gZ = z / SensorManager.GRAVITY_EARTH
// gForce will be close to 1 when there is no movement.
val gForce: Float = sqrt(gX * gX + gY * gY + gZ * gZ)
if (gForce > SHAKE_THRESHOLD_GRAVITY) {
val now = System.currentTimeMillis()
// ignore shake events too close to each other (500ms)
if (mShakeTimestamp + SHAKE_SLOP_TIME_MS > now) {
return
}
// reset the shake count after 3 seconds of no shakes
if (mShakeTimestamp + SHAKE_COUNT_RESET_TIME_MS < now) {
mShakeCount = 0
}
mShakeTimestamp = now
mShakeCount++
mListener!!.onShake(mShakeCount)
}
}
}
companion object {
/*
* The gForce that is necessary to register as shake.
* Must be greater than 1G (one earth gravity unit).
* You can install "G-Force", by Blake La Pierre
* from the Google Play Store and run it to see how
* many G's it takes to register a shake
*/
private const val SHAKE_THRESHOLD_GRAVITY = 2.7f
private const val SHAKE_SLOP_TIME_MS = 500
private const val SHAKE_COUNT_RESET_TIME_MS = 3000
}
}
Your main Activity
class MainActivity : AppCompatActivity() {
// The following are used for the shake detection
private var mSensorManager: SensorManager? = null
private var mAccelerometer: Sensor? = null
private var mShakeDetector: ShakeDetector? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initSensor()
}
override fun onResume() {
super.onResume()
// Add the following line to register the Session Manager Listener onResume
mSensorManager!!.registerListener(
mShakeDetector,
mAccelerometer,
SensorManager.SENSOR_DELAY_UI
)
}
override fun onPause() { // Add the following line to unregister the Sensor Manager onPause
mSensorManager!!.unregisterListener(mShakeDetector)
super.onPause()
}
private fun initSensor() {
// ShakeDetector initialization
// ShakeDetector initialization
mSensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
mAccelerometer = mSensorManager!!.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
mShakeDetector = ShakeDetector()
mShakeDetector!!.setOnShakeListener(object : OnShakeListener {
override fun onShake(count: Int) { /*
* The following method, "handleShakeEvent(count):" is a stub //
* method you would use to setup whatever you want done once the
* device has been shook.
*/
Toast.makeText(this#MainActivity, count.toString(), Toast.LENGTH_SHORT).show()
}
})
}
}
Finally add this code to Manifests to make sure the phone has an accelerometer
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
You can use Seismic:
See the code here:
https://github.com/square/seismic/blob/master/library/src/main/java/com/squareup/seismic/ShakeDetector.java
Do the following:
private float xAccel, yAccel, zAccel;
private float xPreviousAccel, yPreviousAccel, zPreviousAccel;
private boolean firstUpdate = true;
private final float shakeThreshold = 1.5f;
private boolean shakeInitiated = false;
SensorEventListener mySensorEventListener;
SensorManager mySensorManager;
Put this in onCreate method.
mySensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mySensorManager.registerListener(mySensorEventListener,
mySensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
And now the main part.
private boolean isAccelerationChanged() {
float deltaX = Math.abs(xPreviousAccel - xAccel);
float deltaY = Math.abs(yPreviousAccel - yAccel);
float deltaZ = Math.abs(zPreviousAccel - zAccel);
return (deltaX > shakeThreshold && deltaY > shakeThreshold)
|| (deltaX > shakeThreshold && deltaZ > shakeThreshold)
|| (deltaY > shakeThreshold && deltaZ > shakeThreshold);
}
private void updateAccelParameters(float xNewAccel, float yNewAccel, float zNewAccel) {
if (firstUpdate) {
xPreviousAccel = xNewAccel;
yPreviousAccel = yNewAccel;
zPreviousAccel = zNewAccel;
firstUpdate = false;
}else{
xPreviousAccel = xAccel;
yPreviousAccel = yAccel;
zPreviousAccel = zAccel;
}
xAccel = xNewAccel;
yAccel = yNewAccel;
zAccel = zNewAccel;
}
private void executeShakeAction() {
//this method is called when devices shakes
}
public void onSensorChanged(SensorEvent se) {
updateAccelParameters(se.values[0], se.values[1], se.values[2]);
if ((!shakeInitiated) && isAccelerationChanged()) {
shakeInitiated = true;
}else if ((shakeInitiated) && isAccelerationChanged()){
executeShakeAction();
}else if((shakeInitiated) && (!isAccelerationChanged())){
shakeInitiated = false;
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
//setting the accuracy
}
Dont forget to add this code in your MainActivity.java:
MainActivity.java
mShaker = new ShakeListener(this);
mShaker.setOnShakeListener(new ShakeListener.OnShakeListener () {
public void onShake() {
Toast.makeText(MainActivity.this, "Shake " , Toast.LENGTH_LONG).show();
}
});
#Override
protected void onResume() {
super.onResume();
mShaker.resume();
}
#Override
protected void onPause() {
super.onPause();
mShaker.pause();
}
Or I give you a link about this stuff.

Categories