Why the beep sound makes app crashes? - android

I try to make a level indicator which beeps quicker when the phone reach an horizontal position (using the accelerometer), the beep sound plays after a touch on the screen and stop if screen is touched again.
So I made the following code, and the problem I have is that since I've add the "beep" sound part (with MyRunnable function called in the onTouch event), my app crashes after few seconds (it works fine for few second and I have no error messages after the build).
I really have no clue on what the problem could be. I'm stuck here and need some help, thanks !
public class MainActivity extends AppCompatActivity implements SensorEventListener, View.OnTouchListener {
Sensor mySensor;
SensorManager SM;
float ANGLEX, ANGLEY, ANGLEZ;
int aX, aY, aZ;
int roundANGLEX, roundANGLEY, roundANGLEZ;
int Xetal, Yetal;
double centre;
int Rcentre;
int Rcentre2;
boolean active;
int test;
int i=0;
private Handler myHandler;
private Runnable myRunnable = new Runnable() {
#Override
public void run() {
// Play a periodic beep which accelerates according to Rcentre2
ToneGenerator toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
toneGen1.startTone(ToneGenerator.TONE_PROP_BEEP,150);
myHandler.postDelayed(this,(long) Math.sqrt(Rcentre2*20)+50);
}
};
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Créée notre Sensor Manager
SM = (SensorManager) getSystemService(SENSOR_SERVICE);
//Accéléromètre
mySensor = SM.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
//Registre Sensor Listener
SM.registerListener(this, mySensor, 1000000, 1000000);
((ConstraintLayout) findViewById(R.id.layout_main)).setOnTouchListener((View.OnTouchListener) this);
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
//Pas utilisé
}
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
float z_stable = ((int) ((sensorEvent.values[2]) * 100)) / 100.0f;
ANGLEX = (float) (((float) (Math.acos(sensorEvent.values[0] / 9.807)) * (180 / Math.PI))); //I get the accelerometer's values
ANGLEY = (float) (((float) (Math.acos(sensorEvent.values[1] / 9.807)) * (180 / Math.PI)));
ANGLEZ = (float) (((float) (Math.acos(z_stable / 9.807)) * (180 / Math.PI)));
roundANGLEX = Math.round(ANGLEX);
roundANGLEY = Math.round(ANGLEY);
roundANGLEZ = Math.round(ANGLEZ);
aX = roundANGLEX;
aY = roundANGLEY;
aZ = roundANGLEZ;
Xetal = aX - 88; //Xetal and Yetal are 0 when phone is on plane surface
Yetal = aY - 90; //and go from -90 to +90
centre = Math.sqrt(Xetal * Xetal + Yetal * Yetal); //gives the "distance" from the "center => the smaller centre gets, the closer the phone approach horizontal
Rcentre = (int) Math.round(centre);
Rcentre2 = (int) Math.round(centre * 100);
}
public boolean onTouch(View view, MotionEvent motionEvent) {
if (active == true) {
active = false;
myHandler.removeCallbacks(myRunnable);
}
else if (active == false) {
active = true;
myHandler = new Handler();
myHandler.postDelayed(myRunnable,0);
}
return false;
}
}
Here are the Logcat infos, it seems to shows some problems but I don't know what that means.
logcat information

I found an answer that works for me at ToneGenerator crashes in android 6.0
"it was just about releasing created objects of ToneGenerator because rapidly creating objects of 'ToneGenerator' without releasing them will cause the application to crash."
ToneGenerator toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
toneGen1.startTone(ToneGenerator.TONE_PROP_BEEP,150);
toneGen1.release();
I add toneGen1.release(); and it now works fine.
credits to Mahmoud Farahat.

With a semaphore (tonebusy) that seem working (KOTLIN) :
var tonebusy : Boolean = false
fun beep(i : Int) {
if (tonebusy) {
return
}
else
{
tonebusy = true
val toneGen1 = ToneGenerator(AudioManager.STREAM_MUSIC, 100)
toneGen1.startTone(ToneGenerator.TONE_CDMA_PIP, i)
toneGen1.release();
}
tonebusy = false
}

Related

onAccuryChange always has 3 as value

I am trying to Learn How to detect shaking and tried to make App Detect Shaking
but onAccuryChange always on 3
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
switch(i){
case 2:
txt.setText("Shaked");
break;
case 3:
txt.setText("Default");
break;
default:
txt.setText("Nothing");
break;
}
}
always show "Default"
The TextView Already Have Text="No Actions Yet"
The mobile on Table but it shows "Default" once it run
so why it only gives 3 and how can i make it detect shaking ?
this is the Declaration
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt=(TextView)findViewById(R.id.txt);
sensorManager=(SensorManager)getSystemService(SENSOR_SERVICE);
mAccelerometer=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
#Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
Hello Follow with below steps:
Create interface with name "AccelerometerListener":
public interface AccelerometerListener {
public void onAccelerationChanged(float x, float y, float z);
public void onShake(float force);
}
Create Class name as "MainAccelerometer.java", it is main activity:
public class MainAccelerometer extends Activity implements AccelerometerListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.accelerometer_example_main);
// Check onResume Method to start accelerometer listener
}
public void onAccelerationChanged(float x, float y, float z) {
// TODO Auto-generated method stub
}
public void onShake(float force) {
// Do your stuff here
// Called when Motion Detected
Toast.makeText(getBaseContext(), "Motion detected",
Toast.LENGTH_SHORT).show();
}
#Override
public void onResume() {
super.onResume();
Toast.makeText(getBaseContext(), "onResume Accelerometer Started",
Toast.LENGTH_SHORT).show();
//Check device supported Accelerometer senssor or not
if (AccelerometerManager.isSupported(this)) {
//Start Accelerometer Listening
AccelerometerManager.startListening(this);
}
}
#Override
public void onStop() {
super.onStop();
//Check device supported Accelerometer senssor or not
if (AccelerometerManager.isListening()) {
//Start Accelerometer Listening
AccelerometerManager.stopListening();
Toast.makeText(getBaseContext(), "onStop Accelerometer Stoped",
Toast.LENGTH_SHORT).show();
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i("Sensor", "Service distroy");
//Check device supported Accelerometer senssor or not
if (AccelerometerManager.isListening()) {
//Start Accelerometer Listening
AccelerometerManager.stopListening();
Toast.makeText(getBaseContext(), "onDestroy Accelerometer Stoped",
Toast.LENGTH_SHORT).show();
}
}
}
Create Class name as "AccelerometerManager.java", which act as manager for managing accelerometer.
public class AccelerometerManager {
private static Context aContext=null;
/** Accuracy configuration */
private static float threshold = 15.0f;
private static int interval = 200;
private static Sensor sensor;
private static SensorManager sensorManager;
// you could use an OrientationListener array instead
// if you plans to use more than one listener
private static AccelerometerListener listener;
/** indicates whether or not Accelerometer Sensor is supported */
private static Boolean supported;
/** indicates whether or not Accelerometer Sensor is running */
private static boolean running = false;
/**
* Returns true if the manager is listening to orientation changes
*/
public static boolean isListening() {
return running;
}
/**
* Unregisters listeners
*/
public static void stopListening() {
running = false;
try {
if (sensorManager != null && sensorEventListener != null) {
sensorManager.unregisterListener(sensorEventListener);
}
} catch (Exception e) {}
}
/**
* Returns true if at least one Accelerometer sensor is available
*/
public static boolean isSupported(Context context) {
aContext = context;
if (supported == null) {
if (aContext != null) {
sensorManager = (SensorManager) aContext.
getSystemService(Context.SENSOR_SERVICE);
// Get all sensors in device
List<Sensor> sensors = sensorManager.getSensorList(
Sensor.TYPE_ACCELEROMETER);
supported = new Boolean(sensors.size() > 0);
} else {
supported = Boolean.FALSE;
}
}
return supported;
}
/**
* Configure the listener for shaking
* #param threshold
* minimum acceleration variation for considering shaking
* #param interval
* minimum interval between to shake events
*/
public static void configure(int threshold, int interval) {
AccelerometerManager.threshold = threshold;
AccelerometerManager.interval = interval;
}
/**
* Registers a listener and start listening
* #param accelerometerListener
* callback for accelerometer events
*/
public static void startListening( AccelerometerListener accelerometerListener )
{
sensorManager = (SensorManager) aContext.
getSystemService(Context.SENSOR_SERVICE);
// Take all sensors in device
List<Sensor> sensors = sensorManager.getSensorList(
Sensor.TYPE_ACCELEROMETER);
if (sensors.size() > 0) {
sensor = sensors.get(0);
// Register Accelerometer Listener
running = sensorManager.registerListener(
sensorEventListener, sensor,
SensorManager.SENSOR_DELAY_GAME);
listener = accelerometerListener;
}
}
/**
* Configures threshold and interval
* And registers a listener and start listening
* #param accelerometerListener
* callback for accelerometer events
* #param threshold
* minimum acceleration variation for considering shaking
* #param interval
* minimum interval between to shake events
*/
public static void startListening(
AccelerometerListener accelerometerListener,
int threshold, int interval) {
configure(threshold, interval);
startListening(accelerometerListener);
}
/**
* The listener that listen to events from the accelerometer listener
*/
private static SensorEventListener sensorEventListener =
new SensorEventListener() {
private long now = 0;
private long timeDiff = 0;
private long lastUpdate = 0;
private long lastShake = 0;
private float x = 0;
private float y = 0;
private float z = 0;
private float lastX = 0;
private float lastY = 0;
private float lastZ = 0;
private float force = 0;
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
public void onSensorChanged(SensorEvent event) {
// use the event timestamp as reference
// so the manager precision won't depends
// on the AccelerometerListener implementation
// processing time
now = event.timestamp;
x = event.values[0];
y = event.values[1];
z = event.values[2];
// if not interesting in shake events
// just remove the whole if then else block
if (lastUpdate == 0) {
lastUpdate = now;
lastShake = now;
lastX = x;
lastY = y;
lastZ = z;
Toast.makeText(aContext,"No Motion detected",
Toast.LENGTH_SHORT).show();
} else {
timeDiff = now - lastUpdate;
if (timeDiff > 0) {
/*force = Math.abs(x + y + z - lastX - lastY - lastZ)
/ timeDiff;*/
force = Math.abs(x + y + z - lastX - lastY - lastZ);
if (Float.compare(force, threshold) >0 ) {
//Toast.makeText(Accelerometer.getContext(),
//(now-lastShake)+" >= "+interval, 1000).show();
if (now - lastShake >= interval) {
// trigger shake event
listener.onShake(force);
}
else
{
Toast.makeText(aContext,"No Motion detected",
Toast.LENGTH_SHORT).show();
}
lastShake = now;
}
lastX = x;
lastY = y;
lastZ = z;
lastUpdate = now;
}
else
{
Toast.makeText(aContext,"No Motion detected", Toast.LENGTH_SHORT).show();
}
}
// trigger change event
listener.onAccelerationChanged(x, y, z);
}
};
}
In Manifest, do a entry:
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
Create layout file name as "accelerometer_example_main.xml":
<RelativeLayout xmlns:android="<a class="vglnk" href="http://schemas.android.com/apk/res/android" rel="nofollow"><span>http</span><span>://</span><span>schemas</span><span>.</span><span>android</span><span>.</span><span>com</span><span>/</span><span>apk</span><span>/</span><span>res</span><span>/</span><span>android</span></a>"
xmlns:tools="<a class="vglnk" href="http://schemas.android.com/tools" rel="nofollow"><span>http</span><span>://</span><span>schemas</span><span>.</span><span>android</span><span>.</span><span>com</span><span>/</span><span>tools</span></a>"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainAccelerometer" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Shake / Tilt Your Phone To Get Accelerometer Motion Alerts" />
</RelativeLayout>
Happy Coding.

Why cant I use shake listener in ontouch event?

I have a problem when I am running my android app.
The shake listener cannot be called when I touch down.
My logic is "Send message when I am shaking and touch down button at the same time. But it seems that cannot work for my listener part.
But the android studio cant tell me where is the error or code wrongly.
Here is my button code.
shakeitBtn.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Toast.makeText(getBaseContext(), "Shake!", Toast.LENGTH_SHORT).show();
mShakeDetector = new ShakeDetector(new ShakeDetector.OnShakeListener() {
public void onShake() {
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(300);
status = RELEASE_TO_SEND;
}
});
break;
case MotionEvent.ACTION_UP:
if (status == RELEASE_TO_CANCEL) {
Toast.makeText(getBaseContext(), "Shake canceled", Toast.LENGTH_SHORT).show();
} else {
if (status == RELEASE_TO_SEND) {
DatabaseReference childRoot = rootRoomName.push();
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", userName);
map.put("message", "I AM BUSY!!!".toString());
childRoot.updateChildren(map);
}
else{}
}
break;
case MotionEvent.ACTION_MOVE:
if (event.getY() < 0) {
status = RELEASE_TO_CANCEL;
} else {
}
break;
default:
break;
}
return true;
}
});
#Override
public void onResume() {
chat_room.super.onResume();
mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
}
#Override
public void onPause() {
mSensorManager.unregisterListener(mShakeDetector);
chat_room.super.onPause();
}
Here is my share detector code
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
public class ShakeDetector implements SensorEventListener {
// Minimum acceleration needed to count as a shake movement
private static final int MIN_SHAKE_ACCELERATION = 5;
// Minimum number of movements to register a shake
private static final int MIN_MOVEMENTS = 2;
// Maximum time (in milliseconds) for the whole shake to occur
private static final int MAX_SHAKE_DURATION = 500;
// Arrays to store gravity and linear acceleration values
private float[] mGravity = {0.0f, 0.0f, 0.0f};
private float[] mLinearAcceleration = {0.0f, 0.0f, 0.0f};
// Indexes for x, y, and z values
private static final int X = 0;
private static final int Y = 1;
private static final int Z = 2;
// OnShakeListener that will be notified when the shake is detected
private OnShakeListener mShakeListener;
// Start time for the shake detection
long startTime = 0;
// Counter for shake movements
int moveCount = 0;
// Constructor that sets the shake listener
public ShakeDetector(OnShakeListener shakeListener) {
mShakeListener = shakeListener;
}
#Override
public void onSensorChanged(SensorEvent event) {
// This method will be called when the accelerometer detects a change.
// Call a helper method that wraps code from the Android developer site
setCurrentAcceleration(event);
// Get the max linear acceleration in any direction
float maxLinearAcceleration = getMaxCurrentLinearAcceleration();
// Check if the acceleration is greater than our minimum threshold
if (maxLinearAcceleration > MIN_SHAKE_ACCELERATION) {
long now = System.currentTimeMillis();
// Set the startTime if it was reset to zero
if (startTime == 0) {
startTime = now;
}
long elapsedTime = now - startTime;
// Check if we're still in the shake window we defined
if (elapsedTime > MAX_SHAKE_DURATION) {
// Too much time has passed. Start over!
resetShakeDetection();
} else {
// Keep track of all the movements
moveCount++;
// Check if enough movements have been made to qualify as a shake
if (moveCount > MIN_MOVEMENTS) {
// It's a shake! Notify the listener.
mShakeListener.onShake();
// Reset for the next one!
resetShakeDetection();
}
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Intentionally blank
}
private void setCurrentAcceleration(SensorEvent event) {
/*
* BEGIN SECTION from Android developer site. This code accounts for
* gravity using a high-pass filter
*/
// alpha is calculated as t / (t + dT)
// with t, the low-pass filter's time-constant
// and dT, the event delivery rate
final float alpha = 0.8f;
// Gravity components of x, y, and z acceleration
mGravity[X] = alpha * mGravity[X] + (1 - alpha) * event.values[X];
mGravity[Y] = alpha * mGravity[Y] + (1 - alpha) * event.values[Y];
mGravity[Z] = alpha * mGravity[Z] + (1 - alpha) * event.values[Z];
// Linear acceleration along the x, y, and z axes (gravity effects removed)
mLinearAcceleration[X] = event.values[X] - mGravity[X];
mLinearAcceleration[Y] = event.values[Y] - mGravity[Y];
mLinearAcceleration[Z] = event.values[Z] - mGravity[Z];
/*
* END SECTION from Android developer site
*/
}
private float getMaxCurrentLinearAcceleration() {
// Start by setting the value to the x value
float maxLinearAcceleration = mLinearAcceleration[X];
// Check if the y value is greater
if (mLinearAcceleration[Y] > maxLinearAcceleration) {
maxLinearAcceleration = mLinearAcceleration[Y];
}
// Check if the z value is greater
if (mLinearAcceleration[Z] > maxLinearAcceleration) {
maxLinearAcceleration = mLinearAcceleration[Z];
}
// Return the greatest value
return maxLinearAcceleration;
}
private void resetShakeDetection() {
startTime = 0;
moveCount = 0;
}
// (I'd normally put this definition in it's own .java file)
public interface OnShakeListener {
public void onShake();
}
}
As you said the ShakeDetector works if you start it before the onTouch() I suggest the following:
1) Create a parameter in your Activity/Fragment:
bool vibrateOnShake = false;
2) Init your ShakeDetector outside the onTouch():
mShakeDetector = new ShakeDetector(new ShakeDetector.OnShakeListener() {
public void onShake() {
if (vibrateOnShake) {
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(300);
status = RELEASE_TO_SEND;
}
}
});
3) Update your onTouch():
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
vibrateOnShake = true;
...
break;
...
}
}

Problem with View Invalidate() and Handler

i'm trying to fix this problem for more than 2 days now and have become quite desperate.
I want to write a 'Checkers-like' board game for android. The game engine itself is kinda complete but i have problems with updating the views.
I wrote a little example class to demonstrate my problem:
public class GameEngineView extends View {
private static final String TAG = GameEngineView.class.getSimpleName();
private int px;
private int py;
private int cx;
private int cy;
private boolean players_move;
private int clickx;
private int clicky;
Random rgen;
private RefreshHandler mRedrawHandler = new RefreshHandler();
class RefreshHandler extends Handler {
#Override
public void handleMessage(Message msg) {
GameEngineView.this.update();
GameEngineView.this.invalidate();
Log.d(TAG, "invalidate()");
}
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
public GameEngineView(Context context) {
super(context);
setFocusable(true);
players_move = true;
rgen = new Random();
}
public void update() {
updateGame();
Log.d(TAG, "update -> sleep handler");
mRedrawHandler.sleep(100);
}
public void updateGame() {
if(players_move) {
px = clickx;
py = clicky;
} else {
calcAIMove();
switchMove();
}
}
public void switchMove() {
players_move = !players_move;
}
public void calcAIMove() {
for(int i = 0; i < 20000; i++) {
cx = rgen.nextInt(getWidth());
cy = rgen.nextInt(getHeight());
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, "event");
int eventaction = event.getAction();
if(eventaction == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "action_down");
clickx = (int) event.getX();
clicky = (int) event.getY();
switchMove();
update();
}
return super.onTouchEvent(event);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint green = new Paint();
green.setColor(Color.GREEN);
Paint red = new Paint();
red.setColor(Color.RED);
canvas.drawColor(Color.BLACK);
canvas.drawCircle(px, py, 25, green);
canvas.drawCircle(cx, cy, 25, red);
}
}
The function calcAIMove() just burns time to simulate a real evaluation of the position in a board game.
Now my Problem is: If the player clicks(makes a move) the green ball is first drawn when the ai move calculation has been complete. So both moves are drawn at the same time.
I wonder HOW to accomplish this:
-Player clicks
-green Ball is drawn
-AI calculates
-red ball is drawn
-and so on..
When searching the web i found a lot of game loop examples but they all need a Thread with constant polling.. it should be possible without this since the whole program runs sequentially .. right?
Hoping for advice.
thanks,
Dave
Here is how your game could work:
user makes a move
game view is updated
game switches to CPU's turn
sleep to simulate CPU player thinking (if move computation is trivial)
compute CPU's move
game view is updated
game switches to player's turn
There is no need for constant polling in a turn-based game like this. The only place you should have sleep is in step 4, so you can remove it from the other areas (no need for the old update() method which is just a delayed call to updateGame()).
One way to implement this is to simply delay the call to calcAIMove() and switchMove() by putting it into a Runnable and using Handler.postDelayed() or similar.
I don't see how you are disabling touch events when it is the CPU's turn, which can lead to a host of other problems if switchMove() and update() are still being called...
In your game loop you can use a instance of TimerTask to ensure certain delay between greenBall and some other drawing task. Game tutorials like Snake and LunarLander are great references on when and if you need to invalidate your View. Hope this helps a little!
ok so the answer provided by antonyt helped me solve this.. I provide the corrected code for other interested ones.
public class GameEngineView extends View {
private static final String TAG = GameEngineView.class.getSimpleName();
private int px;
private int py;
private int cx;
private int cy;
private boolean players_move;
private int clickx;
private int clicky;
Random rgen;
/**
* Create a simple handler that we can use to cause animation to happen. We
* set ourselves as a target and we can use the sleep()
* function to cause an update/invalidate to occur at a later date.
*/
private RefreshHandler mRedrawHandler = new RefreshHandler();
class RefreshHandler extends Handler {
#Override
public void handleMessage(Message msg) {
GameEngineView.this.update();
}
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
public GameEngineView(Context context) {
super(context);
setFocusable(true);
players_move = true;
rgen = new Random();
}
public void update() {
if(players_move) {
Log.d(TAG, "new player x");
px = clickx;
py = clicky;
GameEngineView.this.invalidate();
switchMove();
mRedrawHandler.sleep(100);
} else {
Log.d(TAG, "new ai x");
calcAIMove();
GameEngineView.this.invalidate();
switchMove();
}
Log.d(TAG, "update -> sleep handler");
}
public void switchMove() {
players_move = !players_move;
}
public void calcAIMove() {
for(int i = 0; i < 100000; i++) {
cx = rgen.nextInt(getWidth());
cy = rgen.nextInt(getHeight());
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, "event");
int eventaction = event.getAction();
if(players_move && eventaction == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "action_down");
clickx = (int) event.getX();
clicky = (int) event.getY();
update();
}
return super.onTouchEvent(event);
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLACK);
Paint green = new Paint();
green.setColor(Color.GREEN);
Paint red = new Paint();
red.setColor(Color.RED);
canvas.drawCircle(px, py, 25, green);
canvas.drawCircle(cx, cy, 25, red);
}
}

How to refresh app upon shaking the device?

I need to add a shake feature that will refresh my Android application.
All I find of documentation involves implementing the SensorListener, but Eclipse tells me it's deprecated and suggest SensorEventListener.
Anybody that has a nice guide to how I go about creating this shake controller?
Here is an example code.
Put this into your activity class:
/* 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();
}
And add this to your onCreate method:
/* 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;
You can then ask "mAccel" wherever you want in your application for the current acceleration, independent from the axis and cleaned from static acceleration such as gravity.
It will be approx. 0 if there is no movement, and, lets say >2 if the device is shaked.
Based on the comments - to test this:
if (mAccel > 12) {
Toast toast = Toast.makeText(getApplicationContext(), "Device has shaken.", Toast.LENGTH_LONG);
toast.show();
}
Notes:
The accelometer should be deactivated onPause and activated onResume to save resources (CPU, Battery).
The code assumes we are on planet Earth ;-) and initializes the acceleration to earth gravity. Otherwise you would get a strong "shake" when the application starts and "hits" the ground from free-fall. However, the code gets used to the gravitation due to the low-cut filter and would work also on other planets or in free space, once it is initialized.
(you never know how long your application will be in use...;-)
Here is my code for shake gesture detection:
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
/**
* Listener that detects shake gesture.
*/
public class ShakeEventListener implements SensorEventListener {
/** Minimum movement force to consider. */
private static final int MIN_FORCE = 10;
/**
* Minimum times in a shake gesture that the direction of movement needs to
* change.
*/
private static final int MIN_DIRECTION_CHANGE = 3;
/** Maximum pause between movements. */
private static final int MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE = 200;
/** Maximum allowed time for shake gesture. */
private static final int MAX_TOTAL_DURATION_OF_SHAKE = 400;
/** Time when the gesture started. */
private long mFirstDirectionChangeTime = 0;
/** Time when the last movement started. */
private long mLastDirectionChangeTime;
/** How many movements are considered so far. */
private int mDirectionChangeCount = 0;
/** The last x position. */
private float lastX = 0;
/** The last y position. */
private float lastY = 0;
/** The last z position. */
private float lastZ = 0;
/** OnShakeListener that is called when shake is detected. */
private OnShakeListener mShakeListener;
/**
* Interface for shake gesture.
*/
public interface OnShakeListener {
/**
* Called when shake gesture is detected.
*/
void onShake();
}
public void setOnShakeListener(OnShakeListener listener) {
mShakeListener = listener;
}
#Override
public void onSensorChanged(SensorEvent se) {
// get sensor data
float x = se.values[SensorManager.DATA_X];
float y = se.values[SensorManager.DATA_Y];
float z = se.values[SensorManager.DATA_Z];
// calculate movement
float totalMovement = Math.abs(x + y + z - lastX - lastY - lastZ);
if (totalMovement > MIN_FORCE) {
// get time
long now = System.currentTimeMillis();
// store first movement time
if (mFirstDirectionChangeTime == 0) {
mFirstDirectionChangeTime = now;
mLastDirectionChangeTime = now;
}
// check if the last movement was not long ago
long lastChangeWasAgo = now - mLastDirectionChangeTime;
if (lastChangeWasAgo < MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE) {
// store movement data
mLastDirectionChangeTime = now;
mDirectionChangeCount++;
// store last sensor data
lastX = x;
lastY = y;
lastZ = z;
// check how many movements are so far
if (mDirectionChangeCount >= MIN_DIRECTION_CHANGE) {
// check total duration
long totalDuration = now - mFirstDirectionChangeTime;
if (totalDuration < MAX_TOTAL_DURATION_OF_SHAKE) {
mShakeListener.onShake();
resetShakeParameters();
}
}
} else {
resetShakeParameters();
}
}
}
/**
* Resets the shake parameters to their default values.
*/
private void resetShakeParameters() {
mFirstDirectionChangeTime = 0;
mDirectionChangeCount = 0;
mLastDirectionChangeTime = 0;
lastX = 0;
lastY = 0;
lastZ = 0;
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
Add this in your activity:
private SensorManager mSensorManager;
private ShakeEventListener mSensorListener;
...
in onCreate() add:
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensorListener = new ShakeEventListener();
mSensorListener.setOnShakeListener(new ShakeEventListener.OnShakeListener() {
public void onShake() {
Toast.makeText(KPBActivityImpl.this, "Shake!", Toast.LENGTH_SHORT).show();
}
});
and:
#Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mSensorListener,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI);
}
#Override
protected void onPause() {
mSensorManager.unregisterListener(mSensorListener);
super.onPause();
}
Here's yet another implementation that builds on some of the tips in here as well as the code from the Android developer site.
MainActivity.java
public class MainActivity extends Activity {
private ShakeDetector mShakeDetector;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ShakeDetector initialization
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mShakeDetector = new ShakeDetector(new OnShakeListener() {
#Override
public void onShake() {
// Do stuff!
}
});
}
#Override
protected void onResume() {
super.onResume();
mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
}
#Override
protected void onPause() {
mSensorManager.unregisterListener(mShakeDetector);
super.onPause();
}
}
ShakeDetector.java
package com.example.test;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
public class ShakeDetector implements SensorEventListener {
// Minimum acceleration needed to count as a shake movement
private static final int MIN_SHAKE_ACCELERATION = 5;
// Minimum number of movements to register a shake
private static final int MIN_MOVEMENTS = 2;
// Maximum time (in milliseconds) for the whole shake to occur
private static final int MAX_SHAKE_DURATION = 500;
// Arrays to store gravity and linear acceleration values
private float[] mGravity = { 0.0f, 0.0f, 0.0f };
private float[] mLinearAcceleration = { 0.0f, 0.0f, 0.0f };
// Indexes for x, y, and z values
private static final int X = 0;
private static final int Y = 1;
private static final int Z = 2;
// OnShakeListener that will be notified when the shake is detected
private OnShakeListener mShakeListener;
// Start time for the shake detection
long startTime = 0;
// Counter for shake movements
int moveCount = 0;
// Constructor that sets the shake listener
public ShakeDetector(OnShakeListener shakeListener) {
mShakeListener = shakeListener;
}
#Override
public void onSensorChanged(SensorEvent event) {
// This method will be called when the accelerometer detects a change.
// Call a helper method that wraps code from the Android developer site
setCurrentAcceleration(event);
// Get the max linear acceleration in any direction
float maxLinearAcceleration = getMaxCurrentLinearAcceleration();
// Check if the acceleration is greater than our minimum threshold
if (maxLinearAcceleration > MIN_SHAKE_ACCELERATION) {
long now = System.currentTimeMillis();
// Set the startTime if it was reset to zero
if (startTime == 0) {
startTime = now;
}
long elapsedTime = now - startTime;
// Check if we're still in the shake window we defined
if (elapsedTime > MAX_SHAKE_DURATION) {
// Too much time has passed. Start over!
resetShakeDetection();
}
else {
// Keep track of all the movements
moveCount++;
// Check if enough movements have been made to qualify as a shake
if (moveCount > MIN_MOVEMENTS) {
// It's a shake! Notify the listener.
mShakeListener.onShake();
// Reset for the next one!
resetShakeDetection();
}
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Intentionally blank
}
private void setCurrentAcceleration(SensorEvent event) {
/*
* BEGIN SECTION from Android developer site. This code accounts for
* gravity using a high-pass filter
*/
// alpha is calculated as t / (t + dT)
// with t, the low-pass filter's time-constant
// and dT, the event delivery rate
final float alpha = 0.8f;
// Gravity components of x, y, and z acceleration
mGravity[X] = alpha * mGravity[X] + (1 - alpha) * event.values[X];
mGravity[Y] = alpha * mGravity[Y] + (1 - alpha) * event.values[Y];
mGravity[Z] = alpha * mGravity[Z] + (1 - alpha) * event.values[Z];
// Linear acceleration along the x, y, and z axes (gravity effects removed)
mLinearAcceleration[X] = event.values[X] - mGravity[X];
mLinearAcceleration[Y] = event.values[Y] - mGravity[Y];
mLinearAcceleration[Z] = event.values[Z] - mGravity[Z];
/*
* END SECTION from Android developer site
*/
}
private float getMaxCurrentLinearAcceleration() {
// Start by setting the value to the x value
float maxLinearAcceleration = mLinearAcceleration[X];
// Check if the y value is greater
if (mLinearAcceleration[Y] > maxLinearAcceleration) {
maxLinearAcceleration = mLinearAcceleration[Y];
}
// Check if the z value is greater
if (mLinearAcceleration[Z] > maxLinearAcceleration) {
maxLinearAcceleration = mLinearAcceleration[Z];
}
// Return the greatest value
return maxLinearAcceleration;
}
private void resetShakeDetection() {
startTime = 0;
moveCount = 0;
}
// (I'd normally put this definition in it's own .java file)
public interface OnShakeListener {
public void onShake();
}
}
I really liked Peterdk's answer. I took it upon myself to make a coulpe of tweaks to his code .
file: ShakeDetector.java
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.FloatMath;
public class ShakeDetector implements SensorEventListener {
// The gForce that is necessary to register as shake. Must be greater than 1G (one earth gravity unit)
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);
}
}
}
}
Also, don't forget that you need to register an instance of the ShakeDetector with the SensorManager.
// ShakeDetector initialization
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mShakeDetector = new ShakeDetector();
mShakeDetector.setOnShakeListener(new OnShakeListener() {
#Override
public void onShake(int count) {
handleShakeEvent(count);
}
});
mSensorManager.registerListener(mShakeDetector, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
I am developing a motion-detection and shake-detection app for my university project.
Besides the original target of the application, I am splitting the library part (responsible for motion and shake detection) from the app. The code is free, available on SourceForge with the project name "BenderCatch". Documentation I am producing will be ready around mid-september.
http://sf.net/projects/bendercatch
It uses a more precise way to detect shake: watches BOTH the difference of force between SensorEvents AND the oscillations present in X and Y axis when you perform a shake. It can even make a sound (or vibrate) on each oscillation of the shake.
Feel free to ask me more by e-mail at raffaele [at] terzigno [dot] com
I have written a small example for detecting vertical and horizontal shakes and showing a Toast.
public class Accelerometerka2Activity extends Activity implements SensorEventListener {
private float mLastX, mLastY, mLastZ;
private boolean mInitialized;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private final float NOISE = (float) 8.0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mInitialized = false;
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometer , SensorManager.SENSOR_DELAY_NORMAL);
}
protected void onResume() {
super.onResume();
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// can be safely ignored for this demo
}
public void onSensorChanged(SensorEvent event) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
if (!mInitialized) {
mLastX = x;
mLastY = y;
mLastZ = z;
mInitialized = true;
} else {
float deltaX = Math.abs(mLastX - x);
float deltaY = Math.abs(mLastY - y);
float deltaZ = Math.abs(mLastZ - z);
if (deltaX < NOISE) deltaX = (float)0.0;
if (deltaY < NOISE) deltaY = (float)0.0;
if (deltaZ < NOISE) deltaZ = (float)0.0;
mLastX = x;
mLastY = y;
mLastZ = z;
if (deltaX > deltaY) {
Toast.makeText(getBaseContext(), "Horizental", Toast.LENGTH_SHORT).show();
} else if (deltaY > deltaX) {
Toast.makeText(getBaseContext(), "Vertical", Toast.LENGTH_SHORT).show();
}
}
}
}
You can use seismic. An example can be found here.
I have tried several implementations, but would like to share my own.
It uses G-force as unit for the threshold calculation. It makes it a bit easier to understand what is going on, and also with setting a good threshold.
It simply registers a increase in G force and triggers the listener if it exceeds the threshold. It doesn't use any direction thresholds, cause you don't really need that if you just want to register a good shake.
Of-course you need the standard registering and UN-registering of this listener in the Activity.
Also, to check what threshold you need, I recommend the following app (I am not in any way connected to that app)
public class UmitoShakeEventListener implements SensorEventListener {
/**
* The gforce that is necessary to register as shake. (Must include 1G
* gravity)
*/
private final float shakeThresholdInGForce = 2.25F;
private final float gravityEarth = SensorManager.GRAVITY_EARTH;
private OnShakeListener listener;
public void setOnShakeListener(OnShakeListener listener) {
this.listener = listener;
}
public interface OnShakeListener {
public void onShake();
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// ignore
}
#Override
public void onSensorChanged(SensorEvent event) {
if (listener != null) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
float gX = x / gravityEarth;
float gY = y / gravityEarth;
float gZ = z / gravityEarth;
//G-Force will be 1 when there is no movement. (gravity)
float gForce = FloatMath.sqrt(gX * gX + gY * gY + gZ * gZ);
if (gForce > shakeThresholdInGForce) {
listener.onShake();
}
}
}
}
Here is another code for this:
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
public class AccelerometerListener implements SensorEventListener {
private SensorManager sensorManager;
private List<Sensor> sensors;
private Sensor sensor;
private long lastUpdate = -1;
private long currentTime = -1;
private Main parent;
private Timer timer;
private int shakes;
private static final Handler mHandler = new Handler();
private float last_x, last_y, last_z;
private float current_x, current_y, current_z, currenForce;
private static final int FORCE_THRESHOLD = 500;
private final int DATA_X = SensorManager.DATA_X;
private final int DATA_Y = SensorManager.DATA_Y;
private final int DATA_Z = SensorManager.DATA_Z;
public AccelerometerListener(Main parent) {
SensorManager sensorService = (SensorManager) parent
.getSystemService(Context.SENSOR_SERVICE);
this.sensorManager = sensorService;
if (sensorService == null)
return;
this.sensors = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
if (sensors.size() > 0) {
sensor = sensors.get(0);
}
this.parent = parent;
}
public void start() {
if (sensor == null)
return;
sensorManager.registerListener(this, sensor,
SensorManager.SENSOR_DELAY_GAME);
}
public void stop() {
if (sensorManager == null)
return;
sensorManager.unregisterListener(this);
}
public void onAccuracyChanged(Sensor s, int valu) {
}
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
return;
currentTime = System.currentTimeMillis();
if ((currentTime - lastUpdate) > 50) {
long diffTime = (currentTime - lastUpdate);
lastUpdate = currentTime;
current_x = event.values[DATA_X];
current_y = event.values[DATA_Y];
current_z = event.values[DATA_Z];
currenForce = Math.abs(current_x + current_y + current_z - last_x
- last_y - last_z)
/ diffTime * 10000;
if (currenForce > FORCE_THRESHOLD) {
shakeDetected();
}
last_x = current_x;
last_y = current_y;
last_z = current_z;
}
}
private void shakeDetected() {
shakes++;
if (shakes == 1) {
if (timer != null) {
timer.cancel();
}
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
if (shakes > 3) {
mHandler.post(new Runnable() {
public void run() {
// shake
}
});
}
shakes = 0;
}
}, 500);
}
}
}
package anywheresoftware.b4a.student;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.FloatMath;
public class ShakeEventListener 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 int SHAKE_SLOP_TIME_MS = 500;
private static final int SHAKE_COUNT_RESET_TIME_MS = 1000;
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 + getSHAKE_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);
}
}
}
private long getSHAKE_SLOP_TIME_MS() {
// TODO Auto-generated method stub
return SHAKE_SLOP_TIME_MS;
}
public void setSHAKE_SLOP_TIME_MS(int sHAKE_SLOP_TIME_MS) {
SHAKE_SLOP_TIME_MS = sHAKE_SLOP_TIME_MS;
}
}
package com.example.shakingapp;
import android.app.Activity;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
public class MainActivity extends Activity implements SensorEventListener {
private SensorManager sensorManager;
private boolean color = false;
private View view;
private long lastUpdate;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = findViewById(R.id.textView);
view.setBackgroundColor(Color.GREEN);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
lastUpdate = System.currentTimeMillis();
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
getAccelerometer(event);
}
}
private void getAccelerometer(SensorEvent event) {
float[] values = event.values;
// Movement
float x = values[0];
float y = values[1];
float z = values[2];
System.out.println(x);
System.out.println(y);
System.out.println(z);
System.out.println(SensorManager.GRAVITY_EARTH );
float accelationSquareRoot = (x * x + y * y + z * z)
/ (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);
long actualTime = System.currentTimeMillis();
if (accelationSquareRoot >= 2) //
{
if (actualTime - lastUpdate < 200) {
return;
}
lastUpdate = actualTime;
Toast.makeText(this, "Device was shuffed "+accelationSquareRoot, Toast.LENGTH_SHORT)
.show();
if (color) {
view.setBackgroundColor(Color.GREEN);
} else {
view.setBackgroundColor(Color.RED);
}
color = !color;
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
protected void onResume() {
super.onResume();
// register this class as a listener for the orientation and
// accelerometer sensors
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
// unregister listener
super.onPause();
sensorManager.unregisterListener(this);
}
}
Shaker.java
import java.util.ArrayList;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
public class Shaker implements SensorEventListener{
private static final String SENSOR_SERVICE = Context.SENSOR_SERVICE;
private SensorManager sensorMgr;
private Sensor mAccelerometer;
private boolean accelSupported;
private long timeInMillis;
private long threshold;
private OnShakerTreshold listener;
ArrayList<Float> valueStack;
public Shaker(Context context, OnShakerTreshold listener, long timeInMillis, long threshold) {
try {
this.timeInMillis = timeInMillis;
this.threshold = threshold;
this.listener = listener;
if (timeInMillis<100){
throw new Exception("timeInMillis < 100ms");
}
valueStack = new ArrayList<Float>((int)(timeInMillis/100));
sensorMgr = (SensorManager) context.getSystemService(SENSOR_SERVICE);
mAccelerometer = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
} catch (Exception e){
e.printStackTrace();
}
}
public void start() {
try {
accelSupported = sensorMgr.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
if (!accelSupported) {
stop();
throw new Exception("Sensor is not supported");
}
} catch (Exception e){
e.printStackTrace();
}
}
public void stop(){
try {
sensorMgr.unregisterListener(this, mAccelerometer);
} catch (Exception e){
e.printStackTrace();
}
}
#Override
protected void finalize() throws Throwable {
try {
stop();
} catch (Exception e){
e.printStackTrace();
}
super.finalize();
}
long lastUpdate = 0;
private float last_x;
private float last_y;
private float last_z;
public void onSensorChanged(SensorEvent event) {
try {
if (event.sensor == mAccelerometer) {
long curTime = System.currentTimeMillis();
if ((curTime-lastUpdate)>getNumberOfMeasures()){
lastUpdate = System.currentTimeMillis();
float[] values = event.values;
if (valueStack.size()>(int)getNumberOfMeasures())
valueStack.remove(0);
float x = (int)(values[SensorManager.DATA_X]);
float y = (int)(values[SensorManager.DATA_Y]);
float z = (int)(values[SensorManager.DATA_Z]);
float speed = Math.abs((x+y+z) - (last_x + last_y + last_z));
valueStack.add(speed);
String posText = String.format("X:%4.0f Y:%4.0f Z:%4.0f", (x-last_x), (y-last_y), (z-last_z));
last_x = (x);
last_y = (y);
last_z = (z);
float sumOfValues = 0;
float avgOfValues = 0;
for (float f : valueStack){
sumOfValues = (sumOfValues+f);
}
avgOfValues = sumOfValues/(int)getNumberOfMeasures();
if (avgOfValues>=threshold){
listener.onTreshold();
valueStack.clear();
}
System.out.println(String.format("M: %+4d A: %5.0f V: %4.0f %s", valueStack.size(),avgOfValues,speed,posText));
}
}
} catch (Exception e){
e.printStackTrace();
}
}
private long getNumberOfMeasures() {
return timeInMillis/100;
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
public interface OnShakerTreshold {
public void onTreshold();
}
}
MainActivity.java
public class MainActivity extends Activity implements OnShakerTreshold{
private Shaker s;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
s = new Shaker(getApplicationContext(), this, 5000, 20);
// 5000 = 5 second of shaking
// 20 = minimal threshold (very angry shaking :D)
// beware screen rotation reset counter
}
#Override
protected void onResume() {
s.start();
super.onResume();
}
#Override
protected void onPause() {
s.stop();
super.onPause();
}
public void onTreshold() {
System.out.println("FIRE LISTENER");
RingtoneManager.getRingtone(getApplicationContext(), RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)).play();
}
}
Have fun.
// Need to implement SensorListener
public class ShakeActivity extends Activity implements SensorListener {
// For shake motion detection.
private SensorManager sensorMgr;
private long lastUpdate = -1;
private float x, y, z;
private float last_x, last_y, last_z;
private static final int SHAKE_THRESHOLD = 800;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// start motion detection
sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
boolean accelSupported = sensorMgr.registerListener(this,
SensorManager.SENSOR_ACCELEROMETER,
SensorManager.SENSOR_DELAY_GAME);
if (!accelSupported) {
// on accelerometer on this device
sensorMgr.unregisterListener(this,
SensorManager.SENSOR_ACCELEROMETER);
}
}
protected void onPause() {
if (sensorMgr != null) {
sensorMgr.unregisterListener(this,
SensorManager.SENSOR_ACCELEROMETER);
sensorMgr = null;
}
super.onPause();
}
public void onAccuracyChanged(int arg0, int arg1) {
// TODO Auto-generated method stub
}
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) {
// yes, this is a shake action! Do something about it!
}
last_x = x;
last_y = y;
last_z = z;
}
}
}
}
You should subscribe as a SensorEventListener, and get the accelerometer data.
Once you have it, you should monitor for sudden change in direction (sign) of acceleration on a certain axis. It would be a good indication for the 'shake' movement of device.
Working with me v.good
Reference
public class ShakeEventListener implements SensorEventListener {
public final static int SHAKE_LIMIT = 15;
public final static int LITTLE_SHAKE_LIMIT = 5;
private SensorManager mSensorManager;
private float mAccel = 0.00f;
private float mAccelCurrent = SensorManager.GRAVITY_EARTH;
private float mAccelLast = SensorManager.GRAVITY_EARTH;
private ShakeListener listener;
public interface ShakeListener {
public void onShake();
public void onLittleShake();
}
public ShakeEventListener(ShakeListener l) {
Activity a = (Activity) l;
mSensorManager = (SensorManager) a.getSystemService(Context.SENSOR_SERVICE);
listener = l;
registerListener();
}
public ShakeEventListener(Activity a, ShakeListener l) {
mSensorManager = (SensorManager) a.getSystemService(Context.SENSOR_SERVICE);
listener = l;
registerListener();
}
public void registerListener() {
mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}
public void unregisterListener() {
mSensorManager.unregisterListener(this);
}
public void onSensorChanged(SensorEvent se) {
float x = se.values[0];
float y = se.values[1];
float z = se.values[2];
mAccelLast = mAccelCurrent;
mAccelCurrent = (float) FloatMath.sqrt(x*x + y*y + z*z);
float delta = mAccelCurrent - mAccelLast;
mAccel = mAccel * 0.9f + delta;
if(mAccel > SHAKE_LIMIT)
listener.onShake();
else if(mAccel > LITTLE_SHAKE_LIMIT)
listener.onLittleShake();
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}
You might want to try open source tinybus. With it shake detection is as easy as this.
public class MainActivity extends Activity {
private Bus mBus;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
// Create a bus and attach it to activity
mBus = TinyBus.from(this).wire(new ShakeEventWire());
}
#Subscribe
public void onShakeEvent(ShakeEvent event) {
Toast.makeText(this, "Device has been shaken",
Toast.LENGTH_SHORT).show();
}
#Override
protected void onStart() {
super.onStart();
mBus.register(this);
}
#Override
protected void onStop() {
mBus.unregister(this);
super.onStop();
}
}
It uses seismic for shake detection.
I modify #peceps's answer and make kotlin version of it. And I also add LifecycleOwner parameter to make it lifecycle-aware.
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import kotlin.math.abs
/**
* Listener that detects shake gesture.
*/
class ShakeEventListener(
lifecycleOwner: LifecycleOwner,
private val sensorManager: SensorManager,
private val onShake: () -> Unit = {}
) : SensorEventListener, DefaultLifecycleObserver {
/** Time when the gesture started. */
private var mFirstDirectionChangeTime: Long = 0
/** Time when the last movement started. */
private var mLastDirectionChangeTime: Long = 0
/** How many movements are considered so far. */
private var mDirectionChangeCount = 0
/** The last x position. */
private var lastX = 0f
/** The last y position. */
private var lastY = 0f
/** The last z position. */
private var lastZ = 0f
init {
sensorManager.registerListener(
this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI
)
// observe lifecycle state
lifecycleOwner.lifecycle.addObserver(this)
}
override fun onResume(owner: LifecycleOwner) {
sensorManager.registerListener(
this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_UI
)
}
override fun onPause(owner: LifecycleOwner) {
sensorManager.unregisterListener(this)
}
override fun onSensorChanged(se: SensorEvent) {
// get sensor data
val x = se.values[0]
val y = se.values[1]
val z = se.values[2]
// calculate movement
val totalMovement = abs(x + y + z - lastX - lastY - lastZ)
if (totalMovement > MIN_FORCE) {
// get time
val now = System.currentTimeMillis()
// store first movement time
if (mFirstDirectionChangeTime == 0L) {
mFirstDirectionChangeTime = now
mLastDirectionChangeTime = now
}
// check if the last movement was not long ago
val lastChangeWasAgo = now - mLastDirectionChangeTime
if (lastChangeWasAgo < MAX_PAUSE_BETWEEN_DIRECTION_CHANGE) {
// store movement data
mLastDirectionChangeTime = now
mDirectionChangeCount++
// store last sensor data
lastX = x
lastY = y
lastZ = z
// check how many movements are so far
if (mDirectionChangeCount >= MIN_DIRECTION_CHANGE) {
// check total duration
val totalDuration = now - mFirstDirectionChangeTime
if (totalDuration < MAX_TOTAL_DURATION_OF_SHAKE) {
onShake()
resetShakeParameters()
}
}
} else {
resetShakeParameters()
}
}
}
/**
* Resets the shake parameters to their default values.
*/
private fun resetShakeParameters() {
mFirstDirectionChangeTime = 0
mDirectionChangeCount = 0
mLastDirectionChangeTime = 0
lastX = 0f
lastY = 0f
lastZ = 0f
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
companion object {
/** Minimum movement force to consider. */
private const val MIN_FORCE = 10
/**
* Minimum times in a shake gesture that the direction of movement needs to
* change.
*/
private const val MIN_DIRECTION_CHANGE = 3
/** Maximum pause between movements. */
private const val MAX_PAUSE_BETWEEN_DIRECTION_CHANGE = 200
/** Maximum allowed time for shake gesture. */
private const val MAX_TOTAL_DURATION_OF_SHAKE = 400
}
}
In your activity, add this code to make it detecting shake event:
ShakeEventListener(this, sensorManager){
// onShake logic
}

How can I access the accelerometer properly in Android 1.5?

I have seen a few code examples of 1.0 / 1.1 but since a lot of that is deprecated now I was hoping to find a nice 1.5+ example. I have some code here that I wrote but it doesn't really work properly. Any help would be great, thanks!
public class collectAccel extends Activity implements SensorEventListener,
OnClickListener{
private SensorManager sensorMgr;
private TextView xLabel, yLabel, zLabel;
private Button StartBtn;
private List<Sensor> sensorList;
private float x, y, z;
private long lastUpdate = -1;
// deltas for calibration
private float cx, cy, cz;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
xLabel = (TextView) findViewById(R.id.x_label);
yLabel = (TextView) findViewById(R.id.y_label);
zLabel = (TextView) findViewById(R.id.z_label);
StartBtn = (Button) findViewById(R.id.Button1);
StartBtn.setOnClickListener(this);
}
#Override
public void onClick(View arg0) {
if (xLabel.getVisibility() != 1)
xLabel.setVisibility(1);
if (yLabel.getVisibility() != 1)
yLabel.setVisibility(1);
if (zLabel.getVisibility() != 1)
zLabel.setVisibility(1);
}
#Override
protected void onPause() {
super.onPause();
sensorMgr.unregisterListener((SensorEventListener)this, sensorList.get(0));
sensorMgr = null;
cx = 0;
cy = 0;
cz = 0;
}
#Override
protected void onResume() {
super.onResume();
sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorList = sensorMgr.getSensorList(Sensor.TYPE_ACCELEROMETER);
boolean accelSupported = sensorMgr.registerListener((SensorEventListener)this,
sensorList.get(0),
SENSOR_DELAY_UI);
if (!accelSupported) {
// on accelerometer on this device
sensorMgr.unregisterListener((SensorEventListener)this, sensorList.get(0));
}
}
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
cx = 0;
cy = 0;
cz = 0;
}
#Override
public void onSensorChanged(SensorEvent arg0) {
if (arg0.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
long curTime = System.currentTimeMillis();
// only allow one update every 100ms, otherwise updates
// come way too fast and the phone gets bogged down
// with garbage collection
if (lastUpdate == -1 || (curTime - lastUpdate) > 100) {
lastUpdate = curTime;
x = arg0.values[0];
y = arg0.values[1];
z = arg0.values[2];
xLabel.setText(String.format("X: %+2.5f (%+2.5f)", (x+cx), cx));
yLabel.setText(String.format("Y: %+2.5f (%+2.5f)", (y+cy), cy));
zLabel.setText(String.format("Z: %+2.5f (%+2.5f)", (z+cz), cz));
}
}
}
}
You can look it up in the Android Reference but It looks like you'll need
SensorManager mgr = Context.getSystemService(SENSOR_SERVICE);
IList<Sensor> sensorList = mgr.getSensorList(SensorManager.SENSOR_ACCELEROMETER);
If you really want the list, but I think you are actually meant to use SensorManager.RegisterListener(SensorListener listener, int sensors, int rate) or another version of that method.

Categories

Resources