org.mozilla.mozstumbler.service.stumblerthread.motiondetection.LegacyMotionSensor.java Source code

Java tutorial

Introduction

Here is the source code for org.mozilla.mozstumbler.service.stumblerthread.motiondetection.LegacyMotionSensor.java

Source

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.mozstumbler.service.stumblerthread.motiondetection;

import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.support.v4.content.LocalBroadcastManager;

import org.mozilla.mozstumbler.svclocator.services.log.LoggerUtil;

public class LegacyMotionSensor implements IMotionSensor {
    private static final String LOG_TAG = LoggerUtil.makeLogTag(LegacyMotionSensor.class);
    // I'm assuming 30 iterations is good enough to get convergence.
    private static int iterations_for_convergence = 30;
    final SensorManager mSensorManager;
    final SensorEventListener mSensorEventListener = new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
            // This must call a method in the LegacyMotionSensor
            // or else we have no way of instrumenting the class with tests.
            sensorChanged(event.sensor.getType(), event.values);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    };

    private final Context mAppContext;
    private boolean isActive;

    public LegacyMotionSensor(Context ctx) {
        mAppContext = ctx;
        mSensorManager = (SensorManager) mAppContext.getSystemService(Context.SENSOR_SERVICE);
    }

    // Each time the baseline average changes by greater than the threshold,
    // indicate this (see isOverThreshold) and update the baseline average to the current rolling average.
    // So, if the threshold is 1, and the current baseline average is 10,
    // then we need the rolling average to to reach 9 (or 11) for isOverThreshold to return true and
    // then the baseline average is set the rolling average.
    // This 'baseline average' method ensures that changes of acceleration can be detected over any time period.
    class RollingAverage {
        float[] mSamples;
        final float mThreshold;
        int mIdx;
        float mTotal;
        float mBaselineAverage;
        boolean mIsInitialized;

        public RollingAverage(int sampleCount, float changeThreshold) {
            mSamples = new float[sampleCount];
            mThreshold = changeThreshold;
        }

        public boolean isOverThreshold(float val) {
            mTotal -= mSamples[mIdx];
            mTotal += val;
            mSamples[mIdx] = val;
            if (++mIdx == mSamples.length) {
                mIdx = 0;
                float average = average();
                if (!mIsInitialized) {
                    mIsInitialized = true;
                    mBaselineAverage = average;
                } else if (Math.abs(average - mBaselineAverage) > mThreshold) {
                    mBaselineAverage = average;
                    return true;
                }
            }
            return false;
        }

        float average() {
            return mTotal / mSamples.length;
        }

        void clear() {
            mSamples = new float[mSamples.length];
            mIdx = 0;
            mIsInitialized = false;
        }
    }

    final RollingAverage mRollingAverage = new RollingAverage(10, 0.5f);

    /*
     This function is called by the SensorEventListener so that we have something to test.
     Real SensorEvent instances cannot be constructed on a test platform.
     */
    public void sensorChanged(int sensorType, float[] event_values) {
        if (mRollingAverage.isOverThreshold(event_values[0] + event_values[1] + event_values[2])) {
            LocalBroadcastManager.getInstance(mAppContext)
                    .sendBroadcastSync(new Intent(MotionSensor.ACTION_USER_MOTION_DETECTED));
            mRollingAverage.clear();
        }
    }

    @Override
    public void start() {
        mSensorManager.registerListener(mSensorEventListener,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);

        isActive = true;
    }

    @Override
    public void stop() {
        mSensorManager.unregisterListener(mSensorEventListener);
        isActive = false;
    }

    @Override
    public boolean isActive() {
        return isActive;
    }
}