Back to project page getback_gps.
The source code is released under:
GNU General Public License
If you think the Android project getback_gps listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/** * Calculates current orientation from sensors. *// w w w .j a v a 2s . c o m * Copyright (C) 2014-2015 Dieter Adriaenssens * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * @package com.github.ruleant.getback_gps.lib * @author Dieter Adriaenssens <ruleant@users.sourceforge.net> */ package com.github.ruleant.getback_gps.lib; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.preference.PreferenceManager; import com.github.ruleant.getback_gps.SettingsActivity; import java.util.ArrayList; import java.util.EventListener; /** * Calculates current orientation from sensors. * * @author Dieter Adriaenssens <ruleant@users.sourceforge.net> */ public class SensorOrientation implements SensorEventListener { /** * Accelerometer Sensor. */ private Sensor mOrientationSensor; /** * Context of the Android app. */ private Context mContext; /** * Current calculated orientation. */ private double mOrientation = 0; /** * Timestamp in milliseconds when current orientation was calculated. */ private long mOrientationTimestamp = 0; /** * Realtime timestamp in nanoseconds when current orientation was updated. */ private long mOrientationRTTimestamp = 0; /** * Sensor manager. */ private SensorManager mSensorManager; /** * Accelerometer Sensor. */ private Sensor mAccelerometer; /** * Accelerometer Sensor values. */ private float[] mAccelerometerValues; /** * Accelerometer Sensor values timestamp. */ private long mAccelerometerTimestamp; /** * Realtime timestamp in nanoseconds when accelerometer sensor was updated. */ private long mAccelerometerRTTimestamp = 0; /** * Magnetic field sensor. */ private Sensor mMagneticFieldSensor; /** * Magnetic field sensor values. */ private float[] mMagneticFieldValues; /** * Magnetic field sensor values timestamp. */ private long mMagneticFieldTimestamp; /** * Realtime timestamp in nanoseconds when magnetic field sensor was updated. */ private long mMagneticFieldRTTimestamp = 0; /** * Sensor timestamp expiration, * 5 seconds in nanoseconds (5 * 10^9). */ private static final long TIMESTAMP_EXPIRE = 5000 * Tools.MILLI_IN_NANO; /** * Sensor update rate in microseconds. */ private static final int SENSOR_UPDATE_RATE = 200000; /** * Number of sensor value components. */ private static final int SENSOR_VALUES_SIZE = 3; /** * Number of rotation matrix components. */ private static final int MATRIX_SIZE = 9; /** * Low pass filter alpha value. */ private static final float LOW_PASS_ALPHA = 0.6f; /** * Alpha value of circular average * of orientation value calculated from sensors. */ private static final float ALPHA_ORIENTATION_SENSORS = 0.05f; /** * Constructor. * * @param context Context of the Android app * @throws IllegalArgumentException if context is not defined */ public SensorOrientation(final Context context) { if (context == null) { throw new IllegalArgumentException("context is not defined"); } mContext = context; mSensorManager = (SensorManager) mContext.getSystemService( Context.SENSOR_SERVICE); if (hasSensors()) { mAccelerometer = mSensorManager.getDefaultSensor( Sensor.TYPE_ACCELEROMETER); mMagneticFieldSensor = mSensorManager.getDefaultSensor( Sensor.TYPE_MAGNETIC_FIELD); mOrientationSensor = mSensorManager.getDefaultSensor( Sensor.TYPE_ORIENTATION); } } /** * Set acceleration by an event from a TYPE_ACCELERATION sensor. * * @param event Sensor event from TYPE_ACCELEROMETER sensor */ public final void setAcceleration(final SensorEvent event) { if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER // reject values that arrive sooner than the update rate || Tools.isTimestampRecent(event.timestamp, mAccelerometerTimestamp, SENSOR_UPDATE_RATE * Tools.MICRO_IN_NANO)) { return; } mAccelerometerValues = LowPassFilter.filterValueSet(mAccelerometerValues, event.values, LOW_PASS_ALPHA); mAccelerometerTimestamp = event.timestamp; mAccelerometerRTTimestamp = Tools.getTimestampNano(); calculateOrientation(); onOrientationChange(); } /** * Set acceleration by an event from a TYPE_MAGNETIC_FIELD sensor. * * @param event Sensor event from TYPE_MAGNETIC_FIELD sensor */ public final void setMagneticField(final SensorEvent event) { if (event.sensor.getType() != Sensor.TYPE_MAGNETIC_FIELD // reject values that arrive sooner than the update rate || Tools.isTimestampRecent(event.timestamp, mMagneticFieldTimestamp, SENSOR_UPDATE_RATE * Tools.MICRO_IN_NANO)) { return; } mMagneticFieldValues = LowPassFilter.filterValueSet(mMagneticFieldValues, event.values, LOW_PASS_ALPHA); mMagneticFieldTimestamp = event.timestamp; mMagneticFieldRTTimestamp = Tools.getTimestampNano(); calculateOrientation(); onOrientationChange(); } /** * Set orientation by an event from a TYPE_ORIENTATION sensor. * * @param event Sensor event from TYPE_ACCELEROMETER sensor */ public final void setOrientation(final SensorEvent event) { if (event.sensor.getType() != Sensor.TYPE_ORIENTATION // reject values that arrive sooner than the update rate || Tools.isTimestampRecent(event.timestamp, mOrientationTimestamp, SENSOR_UPDATE_RATE * Tools.MICRO_IN_NANO)) { return; } mOrientation = event.values[0]; mOrientationTimestamp = event.timestamp; mOrientationRTTimestamp = Tools.getTimestampNano(); onOrientationChange(); } /** * Checks if an orientation can be provided : * - required sensors are available * - sensor values were recently updated. * * @return true if an orientation can be provided */ public boolean hasOrientation() { return isSensorsEnabled() && mAccelerometer != null && mMagneticFieldSensor != null && isTimestampRecent(mAccelerometerRTTimestamp) && isTimestampRecent(mMagneticFieldRTTimestamp) || (mOrientationSensor != null && isTimestampRecent(mOrientationRTTimestamp)); } /** * Gets current SensorOrientation. * * @return current SensorOrientation */ public double getOrientation() { return mOrientation; } /** * Returns true if the required sensors are available : * - TYPE_MAGNETIC_FIELD * - TYPE_ACCELEROMETER. * * @return true if required sensors are available */ public final boolean hasSensors() { return mSensorManager != null && (mSensorManager.getSensorList( Sensor.TYPE_MAGNETIC_FIELD).size() > 0 && mSensorManager.getSensorList( Sensor.TYPE_ACCELEROMETER).size() > 0 || mSensorManager.getSensorList( Sensor.TYPE_ORIENTATION).size() > 0); } /** * Returns true if use of sensors is enabled * - TYPE_MAGNETIC_FIELD * - TYPE_ACCELEROMETER. * * @return true if sensors are enabled */ public final boolean isSensorsEnabled() { return PreferenceManager.getDefaultSharedPreferences(mContext) .getBoolean( SettingsActivity.KEY_PREF_ENABLE_SENSORS, SettingsActivity.DEFAULT_PREF_ENABLE_SENSORS); } /** * Register for Sensor events of * TYPE_ACCELEROMETER and TYPE_MAGNETIC_FIELD. * * @param listener SensorEventListener */ public final void registerEvents(final SensorEventListener listener) { if (!isSensorsEnabled()) { return; } int sensor = Integer.parseInt( PreferenceManager.getDefaultSharedPreferences(mContext) .getString( SettingsActivity.KEY_PREF_GEO_ORIENTATION_SENSOR, SettingsActivity.DEFAULT_PREF_GEO_ORIENTATION_SENSOR)); // use calculated orientation by default // (until raw sensor value is stable) if (sensor == SettingsActivity.GEO_ORIENTATION_SENSOR_CALCULATED || sensor == SettingsActivity.GEO_ORIENTATION_SENSOR_AUTO && mOrientationSensor != null) { // orientation sensor is deprecated mSensorManager.registerListener( listener, mOrientationSensor, SENSOR_UPDATE_RATE); } else if (mAccelerometer != null && mMagneticFieldSensor != null) { mSensorManager.registerListener( listener, mAccelerometer, SENSOR_UPDATE_RATE); mSensorManager.registerListener( listener, mMagneticFieldSensor, SENSOR_UPDATE_RATE); } } /** * Unregister for Sensor events of * TYPE_ACCELEROMETER and TYPE_MAGNETIC_FIELD. * * @param listener SensorEventListener */ public final void unRegisterEvents(final SensorEventListener listener) { if (mAccelerometer != null && mMagneticFieldSensor != null) { mSensorManager.unregisterListener(listener, mAccelerometer); mSensorManager.unregisterListener(listener, mMagneticFieldSensor); } if (mOrientationSensor != null) { mSensorManager.unregisterListener(listener, mOrientationSensor); } } /** * Calculates current orientation, based on * TYPE_MAGNETIC_FIELD and TYPE_ACCELEROMETER sensor values. * * @return current SensorOrientation */ private double calculateOrientation() { if (mAccelerometerValues == null || mAccelerometerValues.length != SENSOR_VALUES_SIZE || mMagneticFieldValues == null || mMagneticFieldValues.length != SENSOR_VALUES_SIZE) { return 0; } float[] rotationMatrixR = new float[MATRIX_SIZE]; float[] orientationValues = new float[SENSOR_VALUES_SIZE]; if (SensorManager.getRotationMatrix(rotationMatrixR, null, mAccelerometerValues, mMagneticFieldValues)) { orientationValues = SensorManager.getOrientation(rotationMatrixR, orientationValues); if (orientationValues.length == SENSOR_VALUES_SIZE) { mOrientation = CircularAverage.getAverageValue( (float) mOrientation, (float) Math.toDegrees(orientationValues[0]), ALPHA_ORIENTATION_SENSORS); mOrientationTimestamp = Tools.getMax(mMagneticFieldTimestamp, mAccelerometerTimestamp); return mOrientation; } } return 0; } /** * Checks if timestamp is recent. * * @param timestamp timestamp in nanoseconds * @return true if timestamp is recent. */ private boolean isTimestampRecent(final long timestamp) { return Tools.isTimestampNanoRecent(timestamp, TIMESTAMP_EXPIRE); } /** * Event listener interface for SensorOrientation updates. */ public interface OrientationEventListener extends EventListener { /** * Indicates there has been a orientation change. */ void onOrientationChanged(); } /** * List with subscribed listeners. */ private ArrayList<OrientationEventListener> eventListenerList = new ArrayList<OrientationEventListener>(); /** * Adds the listener to eventListenerList. * @param listener SensorOrientation event listener */ public final void addEventListener( final OrientationEventListener listener) { eventListenerList.add(listener); // register listening to events when the first listener is added if (eventListenerList.size() == 1) { registerEvents(this); } } /** * Removes the listener from eventListenerList. * @param listener SensorOrientation event listener */ public final void removeEventListener( final OrientationEventListener listener) { eventListenerList.remove(listener); // unregister listening to events when the last listener is removed if (eventListenerList.size() == 0) { unRegisterEvents(this); } } /** * Notify all event listeners. */ private void onOrientationChange() { for (OrientationEventListener eventListener : eventListenerList) { eventListener.onOrientationChanged(); } } /** * Called when sensor accuracy changes, not implemented. * * @param sensor Sensor that has a changed accuracy * @param accuracy New accuracy */ public final void onAccuracyChanged(final Sensor sensor, final int accuracy) { } /** * Called when a Sensor value changes. * * @param event Sensor event */ public final void onSensorChanged(final SensorEvent event) { switch (event.sensor.getType()) { case Sensor.TYPE_ACCELEROMETER: setAcceleration(event); break; case Sensor.TYPE_MAGNETIC_FIELD: setMagneticField(event); break; case Sensor.TYPE_ORIENTATION: setOrientation(event); break; default: break; } } }