edu.cens.loci.sensors.AccelerometerHandler.java Source code

Java tutorial

Introduction

Here is the source code for edu.cens.loci.sensors.AccelerometerHandler.java

Source

/*******************************************************************************
 * Copyright 2012 The Regents of the University of California
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package edu.cens.loci.sensors;

import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.math.stat.descriptive.moment.Variance;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.PowerManager;
import edu.cens.loci.LociConfig;
import edu.cens.loci.utils.MyLog;

public class AccelerometerHandler implements SensorEventListener {

    private static final String TAG = "AccelerometerHandler";

    private PowerManager.WakeLock mCpuLock;

    public interface AccelerometerListener {
        public void onAccelerometerChanged(long time, float magnitude);
    }

    private Context mCxt;
    private static AccelerometerHandler sInstance;

    public AccelerometerHandler getInstance() {
        return sInstance;
    }

    private SensorManager mSensorService;

    private AccelerometerListener mListener;
    private int mDuration;
    private int mPeriod;
    private int mRate;

    private SensorFloatArray mMagArr;
    //private SensorFloatArray mXArr;
    //private SensorFloatArray mYArr;
    //private SensorFloatArray mZArr;

    private Timer mOnTimer = null;
    private Timer mOffTimer = null;
    private Timer mReportTimer = null;
    private boolean mSensorOn = false;
    private boolean mIsOn = false;

    private PowerManager cpu() {
        return (PowerManager) mCxt.getSystemService(Context.POWER_SERVICE);
    }

    public AccelerometerHandler(Context context, AccelerometerListener listener, int duration, int period,
            int rate) {

        if (duration > period)
            period = duration;

        mCxt = context;
        mListener = listener;
        mDuration = duration;
        mPeriod = period;
        mRate = rate;

        mMagArr = new SensorFloatArray(100);
        //mXArr = new SensorFloatArray(100);
        //mYArr = new SensorFloatArray(100);
        //mZArr = new SensorFloatArray(100);

        sInstance = this;
    }

    public void start() {

        if (mIsOn)
            return;

        mCpuLock = cpu().newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AccelerometerHandler.CpuLock");
        mCpuLock.setReferenceCounted(false);

        mIsOn = true;

        if (mDuration > 0) {
            //mCpuLock.acquire();
            mOnTimer = new Timer("sensorTurnOnTimer");
            mOffTimer = new Timer("sensorTurnOffTimer");

            mOnTimer.scheduleAtFixedRate(new TimerTask() {
                public void run() {
                    mSensorService = (SensorManager) mCxt.getSystemService(Context.SENSOR_SERVICE);

                    synchronized (this) {
                        MyLog.i(LociConfig.D.ACC, TAG, "[ACC] ON ");
                        mCpuLock.acquire();
                        mSensorOn = true;
                        mSensorService.registerListener(sInstance,
                                mSensorService.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), mRate);
                    }
                }
            }, 0, mPeriod);

            mOffTimer.scheduleAtFixedRate(new TimerTask() {
                public void run() {

                    synchronized (this) {
                        MyLog.i(LociConfig.D.ACC, TAG, "[ACC] OFF ");
                        mSensorOn = false;
                        if (mCpuLock.isHeld())
                            mCpuLock.release();
                        mSensorService.unregisterListener(sInstance,
                                mSensorService.getDefaultSensor(Sensor.TYPE_ACCELEROMETER));
                    }
                    // time to turn off sensor -- somehow send data

                    //mXArr.reset();
                    //mYArr.reset();
                    //mZArr.reset();
                    long time = Calendar.getInstance().getTime().getTime();
                    float magVar = getMagnitudeVariance();
                    //LociMobileManagerService.getInstance().eventAccelerometerResult(Calendar.getInstance().getTime().getTime(), magVar);

                    mListener.onAccelerometerChanged(time, magVar);

                    //if (LociMobileManagerService.getInstance().isMDOn()) 
                    //   LociMobileManagerService.getInstance().getSystemDb().updatePowerRow(SystemLogDbAdapter.SENSOR_ACC, System.currentTimeMillis());
                }
            }, mDuration, mPeriod);

        } else {

            mCpuLock.acquire();
            mSensorService = (SensorManager) mCxt.getSystemService(Context.SENSOR_SERVICE);
            mSensorService.registerListener(this, mSensorService.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    mRate);

            mReportTimer = new Timer("SensorReportTimer");
            mReportTimer.scheduleAtFixedRate(new TimerTask() {
                public void run() {
                    // send data
                    long time = Calendar.getInstance().getTime().getTime();
                    float magVar = getMagnitudeVariance();
                    mListener.onAccelerometerChanged(time, magVar);
                    //LociMobileManagerService.getInstance().eventAccelerometerResult(Calendar.getInstance().getTime().getTime(), magVar);
                    //if (LociMobileManagerService.getInstance().isMDOn()) 
                    //   LociMobileManagerService.getInstance().getSystemDb().updatePowerRow(SystemLogDbAdapter.SENSOR_ACC, System.currentTimeMillis());
                }
            }, 0, mDuration);
        }

        //LociMobileManagerService.getInstance().getSystemDb().addPowerRow(SystemLogDbAdapter.SENSOR_ACC, System.currentTimeMillis());
        startChkTimer();
    }

    public boolean isOn() {
        return mIsOn;
    }

    public void stop() {

        if (!mIsOn)
            return;

        mIsOn = false;

        if (mDuration > 0) {
            mOnTimer.cancel();
            mOffTimer.cancel();

            if (mSensorOn) {
                mSensorOn = false;
                mSensorService.unregisterListener(this, mSensorService.getDefaultSensor(Sensor.TYPE_ACCELEROMETER));
            }
            if (mCpuLock.isHeld())
                mCpuLock.release();
        } else {
            if (mSensorOn) {
                mSensorOn = false;
                mSensorService.unregisterListener(this, mSensorService.getDefaultSensor(Sensor.TYPE_ACCELEROMETER));
            }
            mReportTimer.cancel();

            if (mCpuLock.isHeld())
                mCpuLock.release();
        }

        stopChkTimer();
    }

    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // TODO Auto-generated method stub

    }

    public void onSensorChanged(SensorEvent event) {
        if (mSensorOn && mIsOn)
            onSensorChangedLocked(event);
        else
            MyLog.d(LociConfig.D.ACC, TAG,
                    "[ACC] onSensorChagned() : We turned off the sensor, ignore incoming data.");
    }

    private synchronized void onSensorChangedLocked(SensorEvent event) {

        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

            mFlag = true;

            if (mIsOn)
                mMagArr.addMagnitude(event.values[SensorManager.DATA_X], event.values[SensorManager.DATA_Y],
                        event.values[SensorManager.DATA_Z], event.accuracy);

            //mXArr.add(event.values[SensorManager.DATA_X]);
            //mYArr.add(event.values[SensorManager.DATA_Y]);
            //mZArr.add(event.values[SensorManager.DATA_Z]);
        }
    }

    private synchronized float getMagnitudeVariance() {
        float magVar = mMagArr.var();
        mMagArr.reset();
        return magVar;
    }

    public class SensorFloatArray {
        private double[] mArr = null;
        private int mCnt;
        private int mMaxCnt;

        public SensorFloatArray(int maxCnt) {
            mMaxCnt = maxCnt;
            mArr = new double[mMaxCnt];
            mCnt = 0;
        }

        public void reset() {
            mCnt = 0;
        }

        public void add(float val) {
            if (mMaxCnt <= mCnt) {
                //System.out.println("add [reject] mCnt=" + mCnt);
                return;
            }
            mArr[mCnt++] = val;
        }

        public void addMagnitude(float x, float y, float z, int accuracy) {
            if (mMaxCnt <= mCnt) {
                MyLog.w(LociConfig.D.ACC, TAG,
                        "[ACC] Accelerometer data buffer is full! ignore data. mCnt=" + mCnt);
                return;
            }

            if (x == 0 || y == 0 || z == 0) {
                MyLog.i(LociConfig.D.ACC, TAG,
                        String.format("[ACC] Handling outlier... x=%15.12f y=%15.12f z=%15.12f", x, y, z));
                return;
            }

            float mag = (float) Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
            mArr[mCnt++] = mag;

            if (LociConfig.D.ACC) {
                String debugMsg = String.format("[ACC] x=%17.13f  y=%17.13f  z=%17.13f  mag=%15.14f acc=%d", x, y,
                        z, mag, accuracy);
                MyLog.d(LociConfig.D.ACC, TAG, debugMsg);
            }
        }

        public float var() {

            double[] valArr = new double[mCnt];

            if (mCnt == 0)
                return 0;

            for (int i = 0; i < mCnt; i++) {
                valArr[i] = mArr[i];
            }

            Variance var = new Variance();

            double varDouble = var.evaluate(valArr);
            float varFloat = (float) varDouble;

            //Log.d(TAG, "var (double) = " + varDouble + " var (float) = " + varFloat);

            return varFloat;
        }
    }

    private static String TIMER_CHECK_ACC = "timer_check_acc";
    private static String TIMER_RESTART_ACC = "timer_restart_acc";

    private Timer mChkTimer;
    private boolean mFlag = false;

    private void startChkTimer() {
        mFlag = false;
        mChkTimer = new Timer(TIMER_CHECK_ACC);
        mChkTimer.scheduleAtFixedRate(new TimerTask() {
            public void run() {
                if (isOn() && !mFlag) {
                    MyLog.e(LociConfig.D.SYS, TAG,
                            "[ACC] (check timer) Movement Detector is not receiving Accel data. restart handler.");

                    if (isOn())
                        stop();

                    Timer restartTimer = new Timer(TIMER_RESTART_ACC);
                    restartTimer.schedule(new TimerTask() {
                        public void run() {
                            MyLog.e(LociConfig.D.SYS, TAG, "[ACC] (check timer) Restart Accelerometer.");
                            start();
                        }
                    }, 500);

                } else {
                    MyLog.e(LociConfig.D.SYS, TAG, "[ACC] (check timer) Movement Detector OK.");
                }
                mFlag = false;
            }
        }, LociConfig.pAccWatch, LociConfig.pAccWatch);
    }

    private void stopChkTimer() {
        mChkTimer.cancel();
        mFlag = false;
    }
}