package interdroid.swan.sensors.impl; import java.io.IOException; import interdroid.swan.R; import interdroid.swan.sensors.AbstractConfigurationActivity; import interdroid.swan.sensors.AbstractSwanSensor; import android.annotation.TargetApi; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Build; import android.os.Bundle; import android.util.Log; @TargetApi(Build.VERSION_CODES.KITKAT) public class StepCounterSensor extends AbstractSwanSensor implements SensorEventListener{ public static final String TAG = "Step Counter Sensor"; public static class ConfigurationActivity extends AbstractConfigurationActivity { @Override public final int getPreferencesXML() { return R.xml.stepcounter_preferences; } } private Sensor mStepCounter; private SensorManager mSensorManager; private PendingIntent mSensorUpdatePIntent; /** Value of ACCURACY must be one of SensorManager.SENSOR_DELAY_* */ public static final String ACCURACY = "accuracy"; protected static final int HISTORY_SIZE = 30; public static final String ACTION_FLUSH_SENSOR = "interdroid.swan.sensors.impl.StepCounterSensor.FlushSensorData"; /** * Step counter */ public static final String STEP_COUNTER = "step_counter"; @Override public void register(String id, String valuePath, Bundle configuration) throws IOException { updateAccuracy(); } @Override public void unregister(String id) { updateAccuracy(); } @Override public void onDestroySensor() { Log.d(TAG, "onDestroySensor"); mSensorManager.unregisterListener(this); super.onDestroySensor(); } @Override public void onConnected() { SENSOR_NAME = "Step Counter Sensor"; mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mStepCounter = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER); if (mStepCounter == null) Log.e(TAG, "No step counter sensor found on device!"); } @Override public void initDefaultConfiguration(Bundle defaults) { defaults.putInt(ACCURACY, SensorManager.SENSOR_DELAY_NORMAL); } @Override public String[] getValuePaths() { return new String[] { STEP_COUNTER }; } /** * Calculates the maximum sensor report interval, based on the * hardware sensor events buffer size, to avoid dropping steps. * * @param stepCounter The Step Counter sensor * * @return Returns the optimal update interval, in milliseconds */ private static int calcSensorReportInterval(Sensor stepCounter) { // We assume that, normally, a person won't do more than // two steps in a second (worst case: running) final int fifoSize = stepCounter.getFifoReservedEventCount(); if (fifoSize > 1) { return (fifoSize / 2) * 1000; } // In this case, the device seems not to have an HW-backed // sensor events buffer. We're assuming that there's no // batching going on, so we don't really need the alarms. return 0; } /** * Sets up a wakelock-based alarm that allows this service * to retrieve sensor events before they're dropped out of * the FIFO buffer. */ private void setupSensorUpdateAlarm(int interval) { AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + interval, interval, mSensorUpdatePIntent); } @TargetApi(Build.VERSION_CODES.KITKAT) private void updateAccuracy() { mSensorManager.unregisterListener(this); if (registeredConfigurations.size() > 0) { int highestAccuracy = mDefaultConfiguration.getInt(ACCURACY); for (Bundle configuration : registeredConfigurations.values()) { if (configuration == null) { continue; } if (configuration.containsKey(ACCURACY)) { highestAccuracy = Math .min(highestAccuracy, Integer.parseInt(configuration .getString(ACCURACY))); } } highestAccuracy = Math.max(highestAccuracy, SensorManager.SENSOR_DELAY_FASTEST); // We use batching for the step counter sensor final int reportInterval = calcSensorReportInterval(mStepCounter); mSensorManager.registerListener(this, mStepCounter, highestAccuracy, reportInterval /* micro seconds */); if (reportInterval > 0) { Log.i(TAG, "Setting up batched data retrieval every " + reportInterval + " ms"); setupSensorUpdateAlarm(reportInterval); } else { Log.w(TAG, "This device doesn't support events batching!"); } } } /* * @see android.hardware.SensorEventListener */ @Override public void onSensorChanged(SensorEvent event) { Log.d(TAG, "on sensor changed"); if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) { Log.v(TAG, "New step counter event. Value: " + (int)event.values[0]); long now = System.currentTimeMillis(); putValueTrimSize(getValuePaths()[0], null, now, event.values[0]); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { Log.v(TAG, "Sensor accuracy changed. New value: " + accuracy); } }