Android Open Source - getback_gps Sensor Orientation






From Project

Back to project page getback_gps.

License

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.

Java Source Code

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




Java Source Code List

com.github.ruleant.getback_gps.AboutActivity.java
com.github.ruleant.getback_gps.AbstractGetBackGpsActivity.java
com.github.ruleant.getback_gps.DetailsActivity.java
com.github.ruleant.getback_gps.LocationService.java
com.github.ruleant.getback_gps.MainActivity.java
com.github.ruleant.getback_gps.NavigationView.java
com.github.ruleant.getback_gps.SettingsActivity.java
com.github.ruleant.getback_gps.lib.AbstractGeoCoordinate.java
com.github.ruleant.getback_gps.lib.AriadneLocation.java
com.github.ruleant.getback_gps.lib.CardinalDirection.java
com.github.ruleant.getback_gps.lib.CircularAverage.java
com.github.ruleant.getback_gps.lib.CoordinateConverterInterface.java
com.github.ruleant.getback_gps.lib.CoordinateRotation.java
com.github.ruleant.getback_gps.lib.Coordinate.java
com.github.ruleant.getback_gps.lib.Coordinates.java
com.github.ruleant.getback_gps.lib.DebugLevel.java
com.github.ruleant.getback_gps.lib.FormatUtils.java
com.github.ruleant.getback_gps.lib.Latitude.java
com.github.ruleant.getback_gps.lib.Longitude.java
com.github.ruleant.getback_gps.lib.LowPassFilter.java
com.github.ruleant.getback_gps.lib.Navigator.java
com.github.ruleant.getback_gps.lib.SensorOrientation.java
com.github.ruleant.getback_gps.lib.StoredDestination.java
com.github.ruleant.getback_gps.lib.StoredLocation.java
com.github.ruleant.getback_gps.lib.Tools.java
com.github.ruleant.getback_gps.lib.package-info.java
com.github.ruleant.getback_gps.package-info.java
com.github.ruleant.unitconversion.UnitConversionInterface.java
com.github.ruleant.unitconversion.package-info.java