ch.jeda.platform.android.SensorManager.java Source code

Java tutorial

Introduction

Here is the source code for ch.jeda.platform.android.SensorManager.java

Source

/*
 * Copyright (C) 2013 - 2014 by Stefan Rothe
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package ch.jeda.platform.android;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import ch.jeda.event.SensorEvent;
import ch.jeda.event.SensorType;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;

class SensorManager extends Fragment {

    private final EnumSet<SensorType> enabledSensors;
    private final EnumMap<SensorType, Sensor> sensorMap;
    private final EnumMap<SensorType, SensorEventListener> sensorListenerMap;
    private final Map<Sensor, SensorInfo> sensorInfoMap;
    private android.hardware.SensorManager imp;

    SensorManager() {
        this.enabledSensors = EnumSet.noneOf(SensorType.class);
        this.sensorMap = new EnumMap<SensorType, Sensor>(SensorType.class);
        this.sensorListenerMap = new EnumMap<SensorType, SensorEventListener>(SensorType.class);
        this.sensorInfoMap = new HashMap<Sensor, SensorInfo>();
        this.setRetainInstance(true);
    }

    @Override
    public void onAttach(final Activity activity) {
        super.onAttach(activity);
        this.sensorMap.clear();
        this.sensorInfoMap.clear();
        this.sensorListenerMap.clear();
        this.imp = (android.hardware.SensorManager) activity.getSystemService(Activity.SENSOR_SERVICE);
        this.checkAdd(SensorType.ACCELERATION, 1f, 0f, this.imp.getDefaultSensor(Sensor.TYPE_ACCELEROMETER));
        this.checkAdd(SensorType.GRAVITY, 1f, 0f, this.imp.getDefaultSensor(Sensor.TYPE_GRAVITY));
        this.checkAdd(SensorType.LIGHT, 1f, 0f, this.imp.getDefaultSensor(Sensor.TYPE_LIGHT));
        this.checkAdd(SensorType.LINEAR_ACCELERATION, 1f, 0f,
                this.imp.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION));
        // Android returns values in micro Tesla
        this.checkAdd(SensorType.MAGNETIC_FIELD, 1e-6f, 0f, this.imp.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD));
        // Android returns value in hekto Pascal
        this.checkAdd(SensorType.PRESSURE, 100f, 0f, this.imp.getDefaultSensor(Sensor.TYPE_PRESSURE));
        // Android returns value in centimeter
        this.checkAdd(SensorType.PROXIMITY, 0.01f, 0f, this.imp.getDefaultSensor(Sensor.TYPE_PROXIMITY));
        // Android returns value in degrees Celcius
        this.checkAdd(SensorType.TEMPERATURE, 1f, -273.15f, this.imp.getDefaultSensor(Sensor.TYPE_TEMPERATURE));
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
            final Bundle savedInstanceState) {
        return null;
    }

    @Override
    public void onPause() {
        super.onPause();
        for (final SensorType sensorType : this.sensorListenerMap.keySet()) {
            this.deactivateSensor(sensorType);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        for (final SensorType sensorType : this.enabledSensors) {
            this.activateSensor(sensorType);
        }
    }

    boolean isAvailable(final SensorType sensorType) {
        return this.sensorMap.containsKey(sensorType);
    }

    boolean isEnabled(final SensorType sensorType) {
        return this.enabledSensors.contains(sensorType);
    }

    void setEnabled(final SensorType sensorType, final boolean enabled) {
        // Enable sensor only if it is available
        if (enabled && this.sensorMap.containsKey(sensorType)) {
            this.enabledSensors.add(sensorType);
        } else {
            this.enabledSensors.remove(sensorType);
        }

        this.updateListeners();
    }

    private void activateSensor(final SensorType sensorType) {
        final SensorEventListener listener = this.createEventListener(sensorType);
        if (listener != null) {
            this.imp.registerListener(listener, this.sensorMap.get(sensorType),
                    android.hardware.SensorManager.SENSOR_DELAY_UI);
            this.sensorListenerMap.put(sensorType, listener);
        }
    }

    private void checkAdd(final SensorType sensorType, final float factor, final float shift, final Sensor sensor) {
        if (sensor != null) {
            this.sensorMap.put(sensorType, sensor);
            this.sensorInfoMap.put(sensor, new SensorInfo(sensorType, sensor, factor, shift));
        }
    }

    private SensorEventListener createEventListener(final SensorType sensorType) {
        switch (sensorType) {
        case ACCELERATION:
        case GRAVITY:
        case LINEAR_ACCELERATION:
        case MAGNETIC_FIELD:
            return new ThreeDeeSensorHandler((Main) this.getActivity(), this.sensorInfoMap);
        case LIGHT:
        case PRESSURE:
        case PROXIMITY:
        case TEMPERATURE:
            return new ValueSensorHandler((Main) this.getActivity(), this.sensorInfoMap);
        default:
            return null;
        }
    }

    private void deactivateSensor(final SensorType sensorType) {
        final SensorEventListener listener = this.sensorListenerMap.get(sensorType);
        if (listener != null) {
            this.imp.unregisterListener(listener);
            this.sensorListenerMap.remove(sensorType);
        }
    }

    private void updateListeners() {
        for (final SensorType sensorType : this.enabledSensors) {
            if (!this.sensorListenerMap.containsKey(sensorType)) {
                this.activateSensor(sensorType);
            }
        }

        for (final SensorType sensorType : this.sensorListenerMap.keySet()) {
            if (!this.enabledSensors.contains(sensorType)) {
                this.deactivateSensor(sensorType);
            }
        }
    }

    private static class ThreeDeeSensorHandler implements SensorEventListener {

        private final Main activity;
        private final Map<Sensor, SensorInfo> sensorReserveMap;

        ThreeDeeSensorHandler(final Main activity, final Map<Sensor, SensorInfo> sensorReserveMap) {
            this.activity = activity;
            this.sensorReserveMap = sensorReserveMap;
        }

        public void onSensorChanged(final android.hardware.SensorEvent event) {
            final SensorInfo sensorInfo = this.sensorReserveMap.get(event.sensor);
            float x = 0f;
            float y = 0f;
            final float z = event.values[2] * sensorInfo.factor;
            switch (this.activity.getWindowManager().getDefaultDisplay().getRotation()) {
            case Surface.ROTATION_0:
                x = -event.values[0] * sensorInfo.factor;
                y = event.values[1] * sensorInfo.factor;
                break;
            case Surface.ROTATION_90:
                x = event.values[1] * sensorInfo.factor;
                y = event.values[0] * sensorInfo.factor;
                break;
            case Surface.ROTATION_180:
                x = event.values[0] * sensorInfo.factor;
                y = -event.values[1] * sensorInfo.factor;
                break;
            case Surface.ROTATION_270:
                x = -event.values[1] * sensorInfo.factor;
                y = -event.values[0] * sensorInfo.factor;
                break;
            }

            this.activity.postEvent(new SensorEvent(sensorInfo, sensorInfo.sensorType, x, y, z));
        }

        public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
        }
    }

    private static class ValueSensorHandler implements SensorEventListener {

        private final Main activity;
        private final Map<Sensor, SensorInfo> sensorReserveMap;

        ValueSensorHandler(final Main activity, final Map<Sensor, SensorInfo> sensorReserveMap) {
            this.activity = activity;
            this.sensorReserveMap = sensorReserveMap;
        }

        public void onSensorChanged(final android.hardware.SensorEvent event) {
            final SensorInfo sensorInfo = this.sensorReserveMap.get(event.sensor);
            final boolean maxiumum = event.values[0] >= event.sensor.getMaximumRange()
                    || event.values[0] <= -event.sensor.getMaximumRange();
            final float value = event.values[0] * sensorInfo.factor + sensorInfo.shift;
            this.activity.postEvent(new SensorEvent(sensorInfo, sensorInfo.sensorType, maxiumum, value));
        }

        public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
        }
    }

    private static class SensorInfo {

        final float factor;
        final float shift;
        final SensorType sensorType;
        private final Sensor sensor;

        public SensorInfo(final SensorType sensorType, final Sensor sensor, final float factor, final float shift) {
            this.factor = factor;
            this.sensor = sensor;
            this.sensorType = sensorType;
            this.shift = shift;
        }

        @Override
        public String toString() {
            return this.sensor.getName();
        }
    }
}