通过服务进行摇动检测

时间:2015-04-11 03:20:18

标签: java android eclipse adt

我在创建摇动检测服务时遇到问题

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;
}

当我运行此服务时,它会连续打印Toast消息。

如何更改代码,以便在摇动设备时只打印一次吐司信息?

2 个答案:

答案 0 :(得分:1)

你有

float totalMovement = Math.abs(x + y + z - lastX - lastY - lastZ);

您可能应该分别对每个轴进行操作 - 因为每个轴都会独立于其他轴进行更改。

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
}

我做了类似的事情,发现最好首先检查延迟(MAX_PAUSE_BETHWEEN_DIRECTION_CHANGE)。

对于Android API 18,有一个重要的运动传感器,如果Android设备中存在可能对您有效。

请参阅http://developer.android.com/reference/android/hardware/Sensor.html#TYPE_SIGNIFICANT_MOTION

答案 1 :(得分:1)

试试这段代码

<强> 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) {
}
}

<强>清单

<service android:name="com.likith.shakedetector.Background_service" />