I'm working on an android app where I need to display my phone's accelerometer values (X, Y,Z) into textviews. I tried to display it on toast and it worked but couldn't do it for textviews.
here's my code:
/// This for my main page:
package com.sourcey.materiallogindemo;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
public class MainAccelerometer extends Activity implements AccelerometerListener{
private TextView mTxtViewX;
private TextView mTxtViewY;
private TextView mTxtViewZ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_accelerometer);
mTxtViewX = (TextView) findViewById(R.id.textX);
mTxtViewY = (TextView) findViewById(R.id.textY);
mTxtViewZ = (TextView) findViewById(R.id.textZ);
Intent intent = getIntent();
// 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) {
// Called when Motion Detected
Toast.makeText(getBaseContext(), "Motion detected",
Toast.LENGTH_LONG).show();
}
#Override
public void onResume() {
super.onResume();
Toast.makeText(getBaseContext(), "onResume Accelerometer Started",
Toast.LENGTH_LONG).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_LONG).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_LONG).show();
}
}
}
and this is my AccelerometerManager Activity where I want to do the display
import android.content.Context;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
public class AccelerometerManager {
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);
// AXE X
String sx= String.valueOf(x);
Toast toast1=Toast.makeText(aContext,"X="+sx, Toast.LENGTH_SHORT);
TextView mTxtViewX = (TextView) toast1.getView().findViewById(android.R.id.message);
mTxtViewX.setTextColor(Color.GREEN);
//toast1.show();
mTxtViewX.setText(sx);
// AXE Y
String sy= String.valueOf(y);
Toast toast2= Toast.makeText(aContext,"Y="+ sy, Toast.LENGTH_SHORT);
TextView mTxtViewY = (TextView) toast2.getView().findViewById(android.R.id.message);
mTxtViewY.setTextColor(Color.RED);
//toast2.show();
mTxtViewY.setText(sy);
// AXE Z
String sz= String.valueOf(z);
Toast toast3= Toast.makeText(aContext, "Z=" + sz, Toast.LENGTH_SHORT);
TextView mTxtViewZ = (TextView) toast3.getView().findViewById(android.R.id.message);
mTxtViewZ.setTextColor(Color.BLACK);
//toast3.show();
mTxtViewZ.setText(sz);
}
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);
}
};
}
and this is my xml file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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:background="#color/primary_dark"
android:text="Shake/Tilt Your Phone To Get Accelerometer Motion Alerts"
android:id="#+id/textView"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true" />
<TextView android:id="#+id/textX"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:background="#color/base"
android:gravity="center"
android:textSize="16dip"
android:layout_above="#+id/textY"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView android:id="#+id/textY"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:background="#color/abc_search_url_text_normal"
android:gravity="center"
android:textSize="16dip"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="166dp" />
<TextView android:id="#+id/textZ"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:background="#color/accent_material_dark"
android:gravity="center"
android:textSize="16dip"
android:layout_above="#+id/textX"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
You could try to update the TextViews in
public void onAccelerationChanged(float x, float y, float z) {
// TODO Auto-generated method stub
}
You are using the wrong Ids in when finding your view
android.R.id.message
Use the Id you set on your xml.
textX
textY
textZ
use this to display String in TextView
mTxtViewX.setText("text to be displayed");
mTxtViewY.setText("text to be displayed");
mTxtViewZ.setText("text to be displayed");
Warning check that all TextView has correct reference attached to them in findViewById
You have to find the correct textview like this:
TextView mTxtViewX = (TextView) ((MainActivity)aContext).findViewById(R.id.textX);
Related
So I've been writing an app that determines your running speed, and integrates that into a workout routine. As I was new to Android, I did everything in an Activity but I've reached a point where I want to divert the speed calculation portion, and everything involving the GPS to a service, which will be bound to whatever workout is going to need it.
This is the workout activity:
package com.example.stropheum.speedcalculatortest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.IBinder;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.os.Vibrator;
import com.example.stropheum.speedcalculatortest.SpeedCalculationService.SpeedCalculationBinder;
public class SpeedAlarmActivity extends ActionBarActivity {
public SpeedCalculationService speedCalculator;
boolean isBound = false;
final int MILLI_TO_SEC = 1000;
final int SEC_TO_HOUR = 3600;
double currentPace, goalPace;
String paceText;
Vibrator vibrator;
// Allow 15 seconds of error for time calculations
final double MILE_TIME_ERROR = 0.25;
LocationManager locationManager;
LocationListener locationListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = new Intent(this, SpeedCalculationService.class);
startService(i);
bindService(i, speedConnection, Context.BIND_AUTO_CREATE);
// Starts the service for calulating user's speed
//startService(new Intent(getBaseContext(), SpeedCalculationService.class)); // was below bind before
vibrator = (Vibrator) this.getSystemService(Context.VIBRATOR_SERVICE);
setContentView(R.layout.activity_speed_alarm);
double startTime, elapsedTime;
double alertIntervalStart, alertIntervalElapsed;
double speed, goalPace, currentPace;
String paceText = "Waiting for GPS signal";
updatePaceText(paceText);
if (isBound);
// Delays workout until the service finds a signal
while (!speedCalculator.gpsSignalFound());
// Once GPS connection is established, being the workout
paceText = "Begin!";
updatePaceText(paceText);
///////////////////
// Part One Begins
/////////////////
startTime = System.currentTimeMillis();
elapsedTime = 0;
alertIntervalStart = startTime; // Initialize 30 second timer on workout start
goalPace = 10.0;
updateGoalPace(goalPace);
do {
// Update time since last alert
alertIntervalElapsed = System.currentTimeMillis() - alertIntervalStart;
speed = speedCalculator.getCurrentSpeed();
currentPace = 60 / speed;
// Update speed and pace every second
if (elapsedTime >= 1.0 * MILLI_TO_SEC) {
updateSpeed(speed);
updateCurrentPace(currentPace);
}
// Alerts user if 30 seconds have gone by with no change
if (alertIntervalStart >= 30 * MILLI_TO_SEC) {
paceAlert();
alertIntervalStart = System.currentTimeMillis();
}
// If 5 seconds have elapsed and perfect pace, alert user
if (alertIntervalElapsed >= 5 * MILLI_TO_SEC && checkPace(currentPace, goalPace)) {
paceAlert();
alertIntervalStart = System.currentTimeMillis();
}
elapsedTime = System.currentTimeMillis() - startTime;
} while (elapsedTime < 120 * MILLI_TO_SEC);
paceText = "Workout Complete!";
updatePaceText(paceText);
// ///////////////////
// // Part Two Begins
// /////////////////
// startTime = System.currentTimeMillis();
// elapsedTime = 0;
// alertIntervalStart = startTime; // Initialize 30 second timer on workout start
//
// goalPace = 6.0;
//
// do {
//
// elapsedTime = System.currentTimeMillis() - startTime;
// } while (elapsedTime < 60 * MILLI_TO_SEC);
//
//
}
/**
* Checks if the user is running in an acceptable range of the goal pace
* #param currentPace Current speed of the user
* #param goalPace Goal speed of the user
* #return True if the pace is acceptable, false otherwise
*/
private boolean checkPace(double currentPace, double goalPace) {
boolean result = true;
if (currentPace > goalPace + MILE_TIME_ERROR || currentPace < goalPace - MILE_TIME_ERROR) {
result = false;
}
return result;
}
/**
* Updates the display to show the current speed
* #param speed The current speed of the user
*/
private void updateSpeed(double speed) {
final TextView speedVal = (TextView) findViewById(R.id.SpeedVal);
speedVal.setText(String.format("%.2f", speed));
}
/**
* Updates the current estimated mile time
* #param currentPace User's current mile time
*/
private void updateCurrentPace(double currentPace) {
int minutes = (int)currentPace;
int seconds = (int)(((currentPace * 100) % 100) * 0.6);
final TextView emtVal = (TextView) findViewById(R.id.emtVal);
emtVal.setText(String.format("%d:%02d", minutes, seconds));
}
/**
* Updates the current goal mile time
* #param goalPace New goal mile time
*/
private void updateGoalPace(double goalPace) {
int minutes = (int)goalPace;
int seconds = (int)(((goalPace * 100) % 100) * 0.6);
final TextView gmtVal = (TextView) findViewById(R.id.gmtVal);
gmtVal.setText(String.format("%d:%02d", minutes, seconds));
}
/**
* Updates the current pace text
* #param paceText indicator for user;s current speed in relation to goal time
*/
private void updatePaceText(String paceText) {
final TextView pace = (TextView) findViewById(R.id.paceView);
pace.setText(paceText);
}
/**
* Checks current pace and assigns appropriate text
*/
private void paceAlert() {
if (currentPace > goalPace + MILE_TIME_ERROR) {
paceText = "Speed up";
vibrator.vibrate(300);
try {
Thread.sleep(300);
} catch (Exception e) {}
vibrator.vibrate(300);
try {
Thread.sleep(300);
} catch (Exception e) {}
vibrator.vibrate(300);
} else if (currentPace < goalPace - MILE_TIME_ERROR) {
paceText = "Slow Down";
vibrator.vibrate(1000);
} else {
paceText = "Perfect Pace!";
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_speed_alarm, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
locationManager.removeUpdates(locationListener);
// Terminate the speed calculation service
stopService(new Intent(getBaseContext(), SpeedCalculationService.class));
finish();
return;
}
ServiceConnection speedConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
SpeedCalculationBinder binder = (SpeedCalculationBinder) service;
speedCalculator = binder.getService();
isBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
}
and this is the service that I've made:
package com.example.stropheum.speedcalculatortest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.widget.Toast;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
public class SpeedCalculationService extends Service {
final int MILLI_TO_SEC = 1000; // Number of milliseconds in a second
final int SEC_TO_HOUR = 3600; // Number of seconds in an hour
private final IBinder binder = new SpeedCalculationBinder();
LocationManager locationManager;
LocationListener locationListener;
boolean firstLocationCheck = true;
// Tracks distance traveled between location calls
double distanceTraveled = 0;
double speed = 0;
public SpeedCalculationService() {
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// This service runs until it is stopped
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
// Tracks the longitude and latitude of the previous and current location calls
double lonNew, lonOld;
double latNew, latOld;
double startTime = System.currentTimeMillis();
double currentTime, timeElapsed;
public void onLocationChanged(Location location) {
if (firstLocationCheck) {
// Prime old locations for first distance calculation
latOld = Math.toRadians(location.getLatitude());
lonOld = Math.toRadians(location.getLongitude());
firstLocationCheck = false;
}
latNew = Math.toRadians(location.getLatitude());
lonNew = Math.toRadians(location.getLongitude());
currentTime = System.currentTimeMillis();
timeElapsed = currentTime - startTime;
distanceTraveled += haversine(latOld, lonOld, latNew, lonNew);
if (distanceTraveled > 1000) { distanceTraveled = 0; } // Handles start errors
speed = distanceTraveled / timeElapsed * MILLI_TO_SEC * SEC_TO_HOUR;
latOld = latNew;
lonOld = lonNew;
}
public void onStatusChanged(String Provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
return START_STICKY;
}
/**
* Computes distance (in miles) between two coordinates using the haversine formula
* #param lat1 latitude of previous location
* #param lon1 longitude of previous location
* #param lat2 latitude of current location
* #param lon2 longitude of current location
* #return distance in miles
*/
private double haversine(double lat1, double lon1, double lat2, double lon2) {
final double EARTH_RADIUS_M = 3959;
double dLon, dLat, a, c, distance;
// Calculate distance traveled using Haversine formula
dLon = lon2 - lon1;
dLat = lat2 - lat1;
a = Math.sin(dLat/2.0) * Math.sin(dLat/2.0) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon/2.0) * Math.sin(dLon/2.0);
System.out.println("a = " + a);
c = 2.0 * Math.atan(Math.sqrt(a));
System.out.println("c = " + c);
distance = EARTH_RADIUS_M * c;
return distance;
}
/**
* Returns the current calculated speed of the user
* #return the current speed in mph format
*/
public double getCurrentSpeed() {
return this.speed;
}
/**
* Method to check if GPS connection is established
* #return true if first location check has been completed
*/
public boolean gpsSignalFound() {
return !this.firstLocationCheck;
}
#Override
public void onDestroy() {
super.onDestroy();
locationManager.removeUpdates(locationListener);
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
// Binder class that will bind to the workout activities
public class SpeedCalculationBinder extends Binder {
SpeedCalculationService getService() {
return SpeedCalculationService.this;
}
}
}
I've managed to narrow down that the errors are coming from the methods in the service returning null values when called, and I added a few debugging lines to determine that the isBound variable is never set to true, so the service is not actually binding to the activity, and I'm pretty sure that's why I'm getting the NullPointerException.
Any help would be wonderful, I can't seem to find anything in my searches here or otherwise as to what my issue is. As far as I can tell, I've bound the service properly. Thanks for your time!
I don't see you starting the service, you should do something like:
Intent intent = new Intent(this, SpeedCalculationService.class);
startService(intent);
bindService(intent, speedConnection, Context.BIND_AUTO_CREATE);
You need to make sure you are using the same intent when starting and binding the service.
Here is some documentation for "Context.BIND_AUTO_CREATE":
* Flag for {#link #bindService}: automatically create the service as long
* as the binding exists. Note that while this will create the service,
* its {#link android.app.Service#onStartCommand}
* method will still only be called due to an
* explicit call to {#link #startService}. Even without that, though,
* this still provides you with access to the service object while the
* service is created.
Notice that onCommandStart is only called with an explicit call to startService.
I'm having a problem creating a shake detection service
background_service
package com.likith.shakedetector;
import android.app.Service;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.IBinder;
import android.widget.Toast;
public class Background_service extends Service implements SensorEventListener
{
SensorManager sensorManager;
int count=0;
private float lastX = 0;
private float lastY = 0;
private float lastZ = 0;
private static final int MIN_FORCE = 10;
private static final int MIN_DIRECTION_CHANGE = 3;
private static final int MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE = 200;
private static final int MAX_TOTAL_DURATION_OF_SHAKE = 400;
private long mFirstDirectionChangeTime = 0;
private long mLastDirectionChangeTime;
private int mDirectionChangeCount = 0;
#Override
public IBinder onBind(Intent intent) {
return null;
}
public void onCreate()
{
super.onCreate();
}
public void onDestroy()
{
super.onDestroy();
sensorManager.unregisterListener(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.registerListener(this,sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_UI);
return START_STICKY;
}
public void onStart(Intent intent, int startId)
{
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
sensorManager.registerListener(this,sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_UI);
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
#SuppressWarnings("deprecation")
private void getAccelerometer(SensorEvent event)
{
//Toast.makeText(getApplicationContext(),"Shaked",Toast.LENGTH_LONG).show();
float x = event.values[SensorManager.DATA_X];
float y = event.values[SensorManager.DATA_Y];
float z = event.values[SensorManager.DATA_Z];
float totalMovement = Math.abs(x + y + z - lastX - lastY - lastZ);
if (totalMovement <= MIN_FORCE)
{
long now = System.currentTimeMillis();
if (mFirstDirectionChangeTime == 0)
{
mFirstDirectionChangeTime = now;
mLastDirectionChangeTime = now;
}
long lastChangeWasAgo = now - mLastDirectionChangeTime;
if (lastChangeWasAgo < MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE)
{
mLastDirectionChangeTime = now;
mDirectionChangeCount++;
lastX = x;
lastY = y;
lastZ = z;
if (mDirectionChangeCount >= MIN_DIRECTION_CHANGE)
{
long totalDuration = now - mFirstDirectionChangeTime;
if (totalDuration < MAX_TOTAL_DURATION_OF_SHAKE)
{
Toast.makeText(getApplicationContext(),"Shaked",Toast.LENGTH_LONG).show();
resetShakeParameters();
}
}
}
else
{
resetShakeParameters();
}
}
}
public void onSensorChanged(SensorEvent event)
{
getAccelerometer(event);
}
protected void onResume()
{
sensorManager.registerListener(this,sensorManager
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_UI);
}
protected void onPause()
{
sensorManager.unregisterListener(this);
}
private void resetShakeParameters()
{
mFirstDirectionChangeTime = 0;
mDirectionChangeCount = 0;
mLastDirectionChangeTime = 0;
lastX = 0;
lastY = 0;
lastZ = 0;
}
When I run this service, It prints the toast message continuously.
How do I change the code so that when I shake the device, it only prints the toast message once?
You have
float totalMovement = Math.abs(x + y + z - lastX - lastY - lastZ);
You probably should do each axis separately - as each axis changes independent of the others.
float xMovement = Math.abs(x - lastX);
float yMovement = Math.abs(y - lastY);
float zMovement = Math.abs(z - lastZ);
if ((xMovement > MIN_FORCE) ||
(yMovement > MIN_FORCE) ||
(zMovement > MIN_FORCE)) {
// motion detected
}
I was doing something similar and found it better to check for the delay (MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE) first.
With Android API 18 there is a significant motion sensor, if present in the Android device may be effective for your purposes.
See http://developer.android.com/reference/android/hardware/Sensor.html#TYPE_SIGNIFICANT_MOTION
try this code
Background_service.java
package com.likith.shakedetector;
import com.likith.gesturelauncherPro.gestureDrawer;
import android.app.Service;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.os.IBinder;
public class Background_service extends Service implements com.likith.shakedetector.shake.Listener
{
#Override
public void onCreate()
{
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
shake sd = new shake(this);
sd.start(sensorManager);
}
#Override
public void hearShake()
{
//Toast.makeText(getApplicationContext(),"Shaked",Toast.LENGTH_LONG).show();
Intent notificationIntent = new Intent(this, gestureDrawer.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(notificationIntent);
}
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
shake.java
package com.likith.shakedetector;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import java.util.ArrayList;
import java.util.List;
/**
* Detects phone shaking. If > 75% of the samples taken in the past 0.5s are
* accelerating, the device is a) shaking, or b) free falling 1.84m (h =
* 1/2*g*t^2*3/4).
*
* #author Bob Lee (bob#squareup.com)
* #author Eric Burke (eric#squareup.com)
*/
public class shake implements SensorEventListener
{
private static final int ACCELERATION_THRESHOLD = 13;
public interface Listener
{
void hearShake();
}
private final SampleQueue queue = new SampleQueue();
private final Listener listener;
private SensorManager sensorManager;
private Sensor accelerometer;
public shake(Listener listener)
{
this.listener = listener;
}
public boolean start(SensorManager sensorManager)
{
if (accelerometer != null)
{
return true;
}
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
// If this phone has an accelerometer, listen to it.
if (accelerometer != null)
{
this.sensorManager = sensorManager;
sensorManager.registerListener(this, accelerometer,SensorManager.SENSOR_DELAY_FASTEST);
}
return accelerometer != null;
}
/**
* Stops listening. Safe to call when already stopped. Ignored on devices
* without appropriate hardware.
*/
public void stop()
{
if (accelerometer != null)
{
sensorManager.unregisterListener(this, accelerometer);
sensorManager = null;
accelerometer = null;
}
}
#Override public void onSensorChanged(SensorEvent event)
{
boolean accelerating = isAccelerating(event);
long timestamp = event.timestamp;
queue.add(timestamp, accelerating);
if (queue.isShaking())
{
queue.clear();
listener.hearShake();
}
}
/** Returns true if the device is currently accelerating. */
private boolean isAccelerating(SensorEvent event)
{
float ax = event.values[0];
float ay = event.values[1];
float az = event.values[2];
// Instead of comparing magnitude to ACCELERATION_THRESHOLD,
// compare their squares. This is equivalent and doesn't need the
// actual magnitude, which would be computed using (expesive) Math.sqrt().
final double magnitudeSquared = ax * ax + ay * ay + az * az;
return magnitudeSquared > ACCELERATION_THRESHOLD * ACCELERATION_THRESHOLD;
}
/** Queue of samples. Keeps a running average. */
static class SampleQueue
{
/** Window size in ns. Used to compute the average. */
private static final long MAX_WINDOW_SIZE = 500000000; // 0.5s
private static final long MIN_WINDOW_SIZE = MAX_WINDOW_SIZE >> 1; // 0.25s
/**
* Ensure the queue size never falls below this size, even if the device
* fails to deliver this many events during the time window. The LG Ally
* is one such device.
*/
private static final int MIN_QUEUE_SIZE = 4;
private final SamplePool pool = new SamplePool();
private Sample oldest;
private Sample newest;
private int sampleCount;
private int acceleratingCount;
/**
* Adds a sample.
*
* #param timestamp in nanoseconds of sample
* #param accelerating true if > {#link #ACCELERATION_THRESHOLD}.
*/
void add(long timestamp, boolean accelerating)
{
// Purge samples that proceed window.
purge(timestamp - MAX_WINDOW_SIZE);
// Add the sample to the queue.
Sample added = pool.acquire();
added.timestamp = timestamp;
added.accelerating = accelerating;
added.next = null;
if (newest != null)
{
newest.next = added;
}
newest = added;
if (oldest == null)
{
oldest = added;
}
// Update running average.
sampleCount++;
if (accelerating)
{
acceleratingCount++;
}
}
/** Removes all samples from this queue. */
void clear() {
while (oldest != null) {
Sample removed = oldest;
oldest = removed.next;
pool.release(removed);
}
newest = null;
sampleCount = 0;
acceleratingCount = 0;
}
/** Purges samples with timestamps older than cutoff. */
void purge(long cutoff) {
while (sampleCount >= MIN_QUEUE_SIZE
&& oldest != null && cutoff - oldest.timestamp > 0) {
// Remove sample.
Sample removed = oldest;
if (removed.accelerating) {
acceleratingCount--;
}
sampleCount--;
oldest = removed.next;
if (oldest == null) {
newest = null;
}
pool.release(removed);
}
}
/** Copies the samples into a list, with the oldest entry at index 0. */
List<Sample> asList() {
List<Sample> list = new ArrayList<Sample>();
Sample s = oldest;
while (s != null) {
list.add(s);
s = s.next;
}
return list;
}
/**
* Returns true if we have enough samples and more than 3/4 of those samples
* are accelerating.
*/
boolean isShaking() {
return newest != null
&& oldest != null
&& newest.timestamp - oldest.timestamp >= MIN_WINDOW_SIZE
&& acceleratingCount >= (sampleCount >> 1) + (sampleCount >> 2);
}
}
/** An accelerometer sample. */
static class Sample {
/** Time sample was taken. */
long timestamp;
/** If acceleration > {#link #ACCELERATION_THRESHOLD}. */
boolean accelerating;
/** Next sample in the queue or pool. */
Sample next;
}
/** Pools samples. Avoids garbage collection. */
static class SamplePool {
private Sample head;
/** Acquires a sample from the pool. */
Sample acquire() {
Sample acquired = head;
if (acquired == null) {
acquired = new Sample();
} else {
// Remove instance from pool.
head = acquired.next;
}
return acquired;
}
/** Returns a sample to the pool. */
void release(Sample sample) {
sample.next = head;
head = sample;
}
}
#Override public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
manifest
<service android:name="com.likith.shakedetector.Background_service" />
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 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.
Ok, bear with me because I haven't worked with custom Dialogs (or Android programming at all really) that much, and I'm sure I've made a stupid beginner mistake.
So I have a simple dice rolling app that I'm trying to incorporate into my existing app, but I want to do it as essentially a popup. The solution I found thus far was to extend a dialog class and use the xml from the app as a custom layout. This actually displays the expected output, but doesn't allow me to interact with it (i.e. it shows dice on screen but I can't roll them!).
The java class I'm calling is this:
import java.io.IOException;
import java.util.Random;
import com.zeldar.scanner.R;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class RollDice extends Activity implements SensorEventListener {
private final int rollAnimations = 50;
private final int delayTime = 15;
private Resources res;
private final int[] diceImages = new int[] { R.drawable.d1, R.drawable.d2, R.drawable.d3, R.drawable.d4, R.drawable.d5, R.drawable.d6 };
private Drawable dice[] = new Drawable[6];
private final Random randomGen = new Random();
#SuppressWarnings("unused")
private int diceSum;
private int roll[] = new int[] { 6, 6 };
private ImageView die1;
private ImageView die2;
private LinearLayout diceContainer;
private SensorManager sensorMgr;
private Handler animationHandler;
private long lastUpdate = -1;
private float x, y, z;
private float last_x, last_y, last_z;
private boolean paused = false;
private static final int UPDATE_DELAY = 50;
private static final int SHAKE_THRESHOLD = 400;
#Override
public void onCreate(Bundle savedInstanceState) {
paused = false;
super.onCreate(savedInstanceState);
setContentView(R.layout.dice);
setTitle(getString(R.string.app_name));
res = getResources();
for (int i = 0; i < 6; i++) {
dice[i] = res.getDrawable(diceImages[i]);
}
diceContainer = (LinearLayout) findViewById(R.id.diceContainer);
diceContainer.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
rollDice();
} catch (Exception e) {};
}
});
die1 = (ImageView) findViewById(R.id.die1);
die2 = (ImageView) findViewById(R.id.die2);
animationHandler = new Handler() {
public void handleMessage(Message msg) {
die1.setImageDrawable(dice[roll[0]]);
die2.setImageDrawable(dice[roll[1]]);
}
};
sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
boolean accelSupported = sensorMgr.registerListener(this,
sensorMgr.getDefaultSensor(SensorManager.SENSOR_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
if (!accelSupported) sensorMgr.unregisterListener(this); //no accelerometer on the device
rollDice();
}
private void rollDice() {
if (paused) return;
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < rollAnimations; i++) {
doRoll();
}
}
}).start();
MediaPlayer mp = MediaPlayer.create(this, R.raw.roll);
try {
mp.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mp.start();
}
private void doRoll() { // only does a single roll
roll[0] = randomGen.nextInt(6);
roll[1] = randomGen.nextInt(6);
diceSum = roll[0] + roll[1] + 2; // 2 is added because the values of the rolls start with 0 not 1
synchronized (getLayoutInflater()) {
animationHandler.sendEmptyMessage(0);
}
try { // delay to alloy for smooth animation
Thread.sleep(delayTime);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
public void onResume() {
super.onResume();
paused = false;
}
public void onPause() {
super.onPause();
paused = true;
}
#Override
public void onSensorChanged(SensorEvent event) {
Sensor mySensor = event.sensor;
if (mySensor.getType() == SensorManager.SENSOR_ACCELEROMETER) {
long curTime = System.currentTimeMillis();
if ((curTime - lastUpdate) > UPDATE_DELAY) {
long diffTime = (curTime - lastUpdate);
lastUpdate = curTime;
x = event.values[SensorManager.DATA_X];
y = event.values[SensorManager.DATA_Y];
z = event.values[SensorManager.DATA_Z];
float speed = Math.abs(x + y + z - last_x - last_y - last_z) / diffTime * 10000;
if (speed > SHAKE_THRESHOLD) { //the screen was shaked
rollDice();
}
last_x = x;
last_y = y;
last_z = z;
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
return; //this method isn't used
}
}
And this is the layout xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/diceContainer"
android:orientation="vertical"
android:gravity="center"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp" >
<ImageView
android:id="#+id/die1"
android:src="#drawable/d6"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginBottom="15dp"
android:contentDescription="#string/content_dice" />
<ImageView
android:id="#+id/die2"
android:src="#drawable/d6"
android:layout_width="150dp"
android:layout_height="150dp"
android:contentDescription="#string/content_dice" />
</LinearLayout>
Finally, the call I'm using to create the dialog:
private Dialog rollDice;
rollDice = new Dialog(ScanActivity.this);
rollDice.setContentView(R.layout.dice);
rollDice.setTitle("Roll Dice");
rollDice.setCancelable(true);
rollDice.show();
To clarify: the most confusing part is that I'm not getting an error, either on compile or run time, it just pops up the window and won't let me do anything with it (except dismiss)!
I would suggest using an activity with a dialog theme if you are wanting something like a dialog. This will allow it to "pop-up" like a dialog but give you more flexibility and easier to manipulate, IMHO. Create a separate activity to open up and add this to your manifest for the activity
<activity android:theme="#android:style/Theme.Dialog">
Themes
There may be a better way to do this but I think this might work well for you.