189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan/* 289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Copyright (C) 2015 The Android Open Source Project 389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * 489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Licensed under the Apache License, Version 2.0 (the "License"); 589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * you may not use this file except in compliance with the License. 689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * You may obtain a copy of the License at 789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * 889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * http://www.apache.org/licenses/LICENSE-2.0 989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * 1089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Unless required by applicable law or agreed to in writing, software 1189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * distributed under the License is distributed on an "AS IS" BASIS, 1289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * See the License for the specific language governing permissions and 1489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * limitations under the License. 1589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 1689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 1789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanpackage com.android.server; 1889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 1989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport android.hardware.Sensor; 2089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport android.hardware.SensorEvent; 2189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport android.hardware.SensorEventListener; 2289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport android.hardware.SensorManager; 2389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport android.os.Handler; 2489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport android.os.Message; 2589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport android.os.PowerManager; 2689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport android.os.SystemClock; 2789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport android.util.Slog; 2889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 2989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanimport java.lang.Float; 3089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 3189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan/** 3289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Determines if the device has been set upon a stationary object. 3389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 3489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayanpublic class AnyMotionDetector { 3589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan interface DeviceIdleCallback { 3689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public void onAnyMotionResult(int result); 3789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 3889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 3989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static final String TAG = "AnyMotionDetector"; 4089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 4189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static final boolean DEBUG = false; 4289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 4389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** Stationary status is unknown due to insufficient orientation measurements. */ 4489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public static final int RESULT_UNKNOWN = -1; 4589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 4689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** Device is stationary, e.g. still on a table. */ 4789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public static final int RESULT_STATIONARY = 0; 4889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 4989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** Device has been moved. */ 5089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public static final int RESULT_MOVED = 1; 5189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 5289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** Orientation measurements are being performed or are planned. */ 5389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static final int STATE_INACTIVE = 0; 5489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 5589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** No orientation measurements are being performed or are planned. */ 5689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static final int STATE_ACTIVE = 1; 5789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 5889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** Current measurement state. */ 5989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private int mState; 6089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 6189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** Threshold energy above which the device is considered moving. */ 6289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private final float THRESHOLD_ENERGY = 5f; 6389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 6489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** The duration of the accelerometer orientation measurement. */ 6589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static final long ORIENTATION_MEASUREMENT_DURATION_MILLIS = 2500; 6689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 6789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** The maximum duration we will collect accelerometer data. */ 6889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static final long ACCELEROMETER_DATA_TIMEOUT_MILLIS = 3000; 6989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 7089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** The interval between accelerometer orientation measurements. */ 7189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static final long ORIENTATION_MEASUREMENT_INTERVAL_MILLIS = 5000; 7289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 73dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan /** The maximum duration we will hold a wakelock to determine stationary status. */ 74dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan private static final long WAKELOCK_TIMEOUT_MILLIS = 30000; 75dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan 7689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** 7789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * The duration in milliseconds after which an orientation measurement is considered 7889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * too stale to be used. 7989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 8089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static final int STALE_MEASUREMENT_TIMEOUT_MILLIS = 2 * 60 * 1000; 8189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 8289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** The accelerometer sampling interval. */ 8389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static final int SAMPLING_INTERVAL_MILLIS = 40; 8489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 8589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private final Handler mHandler; 8689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private final Object mLock = new Object(); 8789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private Sensor mAccelSensor; 8889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private SensorManager mSensorManager; 8989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private PowerManager.WakeLock mWakeLock; 9089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 9123d681bb90a4c70d47da895c883b1fdc0854d49aJoe LaPenna /** Threshold angle in degrees beyond which the device is considered moving. */ 9223d681bb90a4c70d47da895c883b1fdc0854d49aJoe LaPenna private final float mThresholdAngle; 9323d681bb90a4c70d47da895c883b1fdc0854d49aJoe LaPenna 9489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** The minimum number of samples required to detect AnyMotion. */ 9589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private int mNumSufficientSamples; 9689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 9789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** True if an orientation measurement is in progress. */ 9889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private boolean mMeasurementInProgress; 9989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 1007510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro /** True if sendMessageDelayed() for the mMeasurementTimeout callback has been scheduled */ 1017510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro private boolean mMeasurementTimeoutIsActive; 1027510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro 1037510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro /** True if sendMessageDelayed() for the mWakelockTimeout callback has been scheduled */ 1047510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro private boolean mWakelockTimeoutIsActive; 1057510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro 1067510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro /** True if sendMessageDelayed() for the mSensorRestart callback has been scheduled */ 1077510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro private boolean mSensorRestartIsActive; 1087510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro 10989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** The most recent gravity vector. */ 11089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private Vector3 mCurrentGravityVector = null; 11189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 11289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** The second most recent gravity vector. */ 11389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private Vector3 mPreviousGravityVector = null; 11489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 11589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** Running sum of squared errors. */ 11689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private RunningSignalStats mRunningStats; 11789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 11889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private DeviceIdleCallback mCallback = null; 11989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 12042df4fbe10b5a537fa93ea83f12716300ba0bcdcDianne Hackborn public AnyMotionDetector(PowerManager pm, Handler handler, SensorManager sm, 12123d681bb90a4c70d47da895c883b1fdc0854d49aJoe LaPenna DeviceIdleCallback callback, float thresholdAngle) { 12289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (DEBUG) Slog.d(TAG, "AnyMotionDetector instantiated."); 1235e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan synchronized (mLock) { 1245e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 1255e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mWakeLock.setReferenceCounted(false); 1265e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mHandler = handler; 1275e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mSensorManager = sm; 1285e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mAccelSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 1295e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mMeasurementInProgress = false; 1307510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mMeasurementTimeoutIsActive = false; 1317510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mWakelockTimeoutIsActive = false; 1327510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mSensorRestartIsActive = false; 1335e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mState = STATE_INACTIVE; 1345e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mCallback = callback; 1355e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mThresholdAngle = thresholdAngle; 1365e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mRunningStats = new RunningSignalStats(); 1375e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mNumSufficientSamples = (int) Math.ceil( 1385e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan ((double)ORIENTATION_MEASUREMENT_DURATION_MILLIS / SAMPLING_INTERVAL_MILLIS)); 1395e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan if (DEBUG) Slog.d(TAG, "mNumSufficientSamples = " + mNumSufficientSamples); 1405e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan } 14189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 14289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 14389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /* 14489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Acquire accel data until we determine AnyMotion status. 14589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 14689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public void checkForAnyMotion() { 1475e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan if (DEBUG) { 1485e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan Slog.d(TAG, "checkForAnyMotion(). mState = " + mState); 1495e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan } 15089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (mState != STATE_ACTIVE) { 1515e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan synchronized (mLock) { 1525e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mState = STATE_ACTIVE; 1535e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan if (DEBUG) { 1545e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_ACTIVE."); 1555e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan } 1565e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mCurrentGravityVector = null; 1575e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mPreviousGravityVector = null; 1585e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mWakeLock.acquire(); 159dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan Message wakelockTimeoutMsg = Message.obtain(mHandler, mWakelockTimeout); 160dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan mHandler.sendMessageDelayed(wakelockTimeoutMsg, WAKELOCK_TIMEOUT_MILLIS); 1617510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mWakelockTimeoutIsActive = true; 1625e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan startOrientationMeasurementLocked(); 1635e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan } 16489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 16589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 16689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 16742df4fbe10b5a537fa93ea83f12716300ba0bcdcDianne Hackborn public void stop() { 168dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan synchronized (mLock) { 169dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan if (mState == STATE_ACTIVE) { 1705e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan mState = STATE_INACTIVE; 1715e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE."); 172dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan } 1737510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mHandler.removeCallbacks(mMeasurementTimeout); 1747510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mHandler.removeCallbacks(mSensorRestart); 1757510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mMeasurementTimeoutIsActive = false; 1767510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mSensorRestartIsActive = false; 177dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan if (mMeasurementInProgress) { 178dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan mMeasurementInProgress = false; 179dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan mSensorManager.unregisterListener(mListener); 180dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan } 181dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan mCurrentGravityVector = null; 182dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan mPreviousGravityVector = null; 183dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan if (mWakeLock.isHeld()) { 184dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan mHandler.removeCallbacks(mWakelockTimeout); 1857510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mWakelockTimeoutIsActive = false; 1867510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mWakeLock.release(); 18742df4fbe10b5a537fa93ea83f12716300ba0bcdcDianne Hackborn } 18842df4fbe10b5a537fa93ea83f12716300ba0bcdcDianne Hackborn } 18942df4fbe10b5a537fa93ea83f12716300ba0bcdcDianne Hackborn } 19042df4fbe10b5a537fa93ea83f12716300ba0bcdcDianne Hackborn 1915e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan private void startOrientationMeasurementLocked() { 1925e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan if (DEBUG) Slog.d(TAG, "startOrientationMeasurementLocked: mMeasurementInProgress=" + 19389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mMeasurementInProgress + ", (mAccelSensor != null)=" + (mAccelSensor != null)); 19489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (!mMeasurementInProgress && mAccelSensor != null) { 19589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (mSensorManager.registerListener(mListener, mAccelSensor, 19689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan SAMPLING_INTERVAL_MILLIS * 1000)) { 19789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mMeasurementInProgress = true; 19889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mRunningStats.reset(); 19989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 200dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan Message measurementTimeoutMsg = Message.obtain(mHandler, mMeasurementTimeout); 201dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan mHandler.sendMessageDelayed(measurementTimeoutMsg, ACCELEROMETER_DATA_TIMEOUT_MILLIS); 2027510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mMeasurementTimeoutIsActive = true; 20389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 20489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 20589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 20689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private int stopOrientationMeasurementLocked() { 20789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (DEBUG) Slog.d(TAG, "stopOrientationMeasurement. mMeasurementInProgress=" + 20889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mMeasurementInProgress); 20989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan int status = RESULT_UNKNOWN; 21089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (mMeasurementInProgress) { 21189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mHandler.removeCallbacks(mMeasurementTimeout); 2127510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mMeasurementTimeoutIsActive = false; 2137510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mSensorManager.unregisterListener(mListener); 21489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mMeasurementInProgress = false; 21589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mPreviousGravityVector = mCurrentGravityVector; 21689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mCurrentGravityVector = mRunningStats.getRunningAverage(); 217dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan if (mRunningStats.getSampleCount() == 0) { 218dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan Slog.w(TAG, "No accelerometer data acquired for orientation measurement."); 219dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan } 22089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (DEBUG) { 22189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Slog.d(TAG, "mRunningStats = " + mRunningStats.toString()); 22289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan String currentGravityVectorString = (mCurrentGravityVector == null) ? 22389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan "null" : mCurrentGravityVector.toString(); 22489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan String previousGravityVectorString = (mPreviousGravityVector == null) ? 22589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan "null" : mPreviousGravityVector.toString(); 22689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Slog.d(TAG, "mCurrentGravityVector = " + currentGravityVectorString); 22789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Slog.d(TAG, "mPreviousGravityVector = " + previousGravityVectorString); 22889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 22989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mRunningStats.reset(); 23089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan status = getStationaryStatus(); 23189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (DEBUG) Slog.d(TAG, "getStationaryStatus() returned " + status); 23289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (status != RESULT_UNKNOWN) { 233dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan if (mWakeLock.isHeld()) { 234dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan mHandler.removeCallbacks(mWakelockTimeout); 2357510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mWakelockTimeoutIsActive = false; 2367510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mWakeLock.release(); 237dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan } 2385e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan if (DEBUG) { 2395e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE. status = " + status); 2405e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan } 24189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mState = STATE_INACTIVE; 24289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } else { 24389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /* 24489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Unknown due to insufficient measurements. Schedule another orientation 24589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * measurement. 24689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 24789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (DEBUG) Slog.d(TAG, "stopOrientationMeasurementLocked(): another measurement" + 24889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan " scheduled in " + ORIENTATION_MEASUREMENT_INTERVAL_MILLIS + 24989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan " milliseconds."); 25089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Message msg = Message.obtain(mHandler, mSensorRestart); 25189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mHandler.sendMessageDelayed(msg, ORIENTATION_MEASUREMENT_INTERVAL_MILLIS); 2527510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mSensorRestartIsActive = true; 25389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 25489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 25589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return status; 25689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 25789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 25889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /* 25989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Updates mStatus to the current AnyMotion status. 26089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 26189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public int getStationaryStatus() { 26289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if ((mPreviousGravityVector == null) || (mCurrentGravityVector == null)) { 26389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return RESULT_UNKNOWN; 26489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 26589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Vector3 previousGravityVectorNormalized = mPreviousGravityVector.normalized(); 26689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Vector3 currentGravityVectorNormalized = mCurrentGravityVector.normalized(); 26789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan float angle = previousGravityVectorNormalized.angleBetween(currentGravityVectorNormalized); 26823d681bb90a4c70d47da895c883b1fdc0854d49aJoe LaPenna if (DEBUG) Slog.d(TAG, "getStationaryStatus: angle = " + angle 26923d681bb90a4c70d47da895c883b1fdc0854d49aJoe LaPenna + " energy = " + mRunningStats.getEnergy()); 27023d681bb90a4c70d47da895c883b1fdc0854d49aJoe LaPenna if ((angle < mThresholdAngle) && (mRunningStats.getEnergy() < THRESHOLD_ENERGY)) { 27189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return RESULT_STATIONARY; 27289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } else if (Float.isNaN(angle)) { 27389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** 27489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Floating point rounding errors have caused the angle calcuation's dot product to 27589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * exceed 1.0. In such case, we report RESULT_MOVED to prevent devices from rapidly 27689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * retrying this measurement. 27789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 27889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return RESULT_MOVED; 27989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 28089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan long diffTime = mCurrentGravityVector.timeMillisSinceBoot - 28189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mPreviousGravityVector.timeMillisSinceBoot; 28289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (diffTime > STALE_MEASUREMENT_TIMEOUT_MILLIS) { 28389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (DEBUG) Slog.d(TAG, "getStationaryStatus: mPreviousGravityVector is too stale at " + 28489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan diffTime + " ms ago. Returning RESULT_UNKNOWN."); 28589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return RESULT_UNKNOWN; 28689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 28789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return RESULT_MOVED; 28889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 28989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 29089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private final SensorEventListener mListener = new SensorEventListener() { 29189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan @Override 29289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public void onSensorChanged(SensorEvent event) { 29389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan int status = RESULT_UNKNOWN; 29489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan synchronized (mLock) { 29589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Vector3 accelDatum = new Vector3(SystemClock.elapsedRealtime(), event.values[0], 29689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan event.values[1], event.values[2]); 29789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mRunningStats.accumulate(accelDatum); 29889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 29989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan // If we have enough samples, stop accelerometer data acquisition. 30089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (mRunningStats.getSampleCount() >= mNumSufficientSamples) { 30189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan status = stopOrientationMeasurementLocked(); 30289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 30389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 30489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (status != RESULT_UNKNOWN) { 305dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan mHandler.removeCallbacks(mWakelockTimeout); 3067510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mWakelockTimeoutIsActive = false; 30789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan mCallback.onAnyMotionResult(status); 30889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 30989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 31089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 31189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan @Override 31289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public void onAccuracyChanged(Sensor sensor, int accuracy) { 31389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 31489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan }; 31589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 31689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private final Runnable mSensorRestart = new Runnable() { 31789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan @Override 31889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public void run() { 31989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan synchronized (mLock) { 3207510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro if (mSensorRestartIsActive == true) { 3217510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mSensorRestartIsActive = false; 3227510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro startOrientationMeasurementLocked(); 3237510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro } 32489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 32589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 32689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan }; 32789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 32889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private final Runnable mMeasurementTimeout = new Runnable() { 329dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan @Override 330dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan public void run() { 331dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan int status = RESULT_UNKNOWN; 332dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan synchronized (mLock) { 3337510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro if (mMeasurementTimeoutIsActive == true) { 3347510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mMeasurementTimeoutIsActive = false; 3357510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro if (DEBUG) Slog.i(TAG, "mMeasurementTimeout. Failed to collect sufficient accel " + 3367510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro "data within " + ACCELEROMETER_DATA_TIMEOUT_MILLIS + " ms. Stopping " + 3377510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro "orientation measurement."); 3387510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro status = stopOrientationMeasurementLocked(); 3397510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro if (status != RESULT_UNKNOWN) { 3407510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mHandler.removeCallbacks(mWakelockTimeout); 3417510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mWakelockTimeoutIsActive = false; 3427510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mCallback.onAnyMotionResult(status); 3437510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro } 3447510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro } 345dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan } 346dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan } 347dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan }; 348dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan 349dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan private final Runnable mWakelockTimeout = new Runnable() { 350dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan @Override 351dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan public void run() { 352dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan synchronized (mLock) { 3537510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro if (mWakelockTimeoutIsActive == true) { 3547510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro mWakelockTimeoutIsActive = false; 3557510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro stop(); 3567510fbbcd0c007debda64780a80c6e5dae870b5cNick Vaccaro } 357dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan } 358dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan } 359dcf4701d37ca2ececaa3592f29254150a6da3d27Kevin Gabayan }; 36089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 36189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** 36289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * A timestamped three dimensional vector and some vector operations. 36389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 364b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan public static final class Vector3 { 36589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public long timeMillisSinceBoot; 36689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public float x; 36789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public float y; 36889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public float z; 36989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 37089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public Vector3(long timeMillisSinceBoot, float x, float y, float z) { 37189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan this.timeMillisSinceBoot = timeMillisSinceBoot; 37289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan this.x = x; 37389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan this.y = y; 37489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan this.z = z; 37589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 37689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 377b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan public float norm() { 37889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return (float) Math.sqrt(dotProduct(this)); 37989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 38089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 381b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan public Vector3 normalized() { 38289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan float mag = norm(); 38389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return new Vector3(timeMillisSinceBoot, x / mag, y / mag, z / mag); 38489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 38589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 38689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** 38789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Returns the angle between this 3D vector and another given 3D vector. 38889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Assumes both have already been normalized. 38989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * 39089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * @param other The other Vector3 vector. 39189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * @return angle between this vector and the other given one. 39289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 39389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public float angleBetween(Vector3 other) { 394b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan Vector3 crossVector = cross(other); 395b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan float degrees = Math.abs((float)Math.toDegrees( 396b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan Math.atan2(crossVector.norm(), dotProduct(other)))); 39789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Slog.d(TAG, "angleBetween: this = " + this.toString() + 398b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan ", other = " + other.toString() + ", degrees = " + degrees); 399b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan return degrees; 400b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan } 401b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan 402b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan public Vector3 cross(Vector3 v) { 403b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan return new Vector3( 404b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan v.timeMillisSinceBoot, 405b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan y * v.z - z * v.y, 406b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan z * v.x - x * v.z, 407b070577d35436ca0f5463e6ed19a28ae431cfbfbKevin Gabayan x * v.y - y * v.x); 40889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 40989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 41089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan @Override 41189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public String toString() { 41289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan String msg = ""; 41389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan msg += "timeMillisSinceBoot=" + timeMillisSinceBoot; 41489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan msg += " | x=" + x; 41589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan msg += ", y=" + y; 41689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan msg += ", z=" + z; 41789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return msg; 41889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 41989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 42089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public float dotProduct(Vector3 v) { 42189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return x * v.x + y * v.y + z * v.z; 42289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 42389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 42489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public Vector3 times(float val) { 42589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return new Vector3(timeMillisSinceBoot, x * val, y * val, z * val); 42689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 42789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 42889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public Vector3 plus(Vector3 v) { 42989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return new Vector3(v.timeMillisSinceBoot, x + v.x, y + v.y, z + v.z); 43089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 43189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 43289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public Vector3 minus(Vector3 v) { 43389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return new Vector3(v.timeMillisSinceBoot, x - v.x, y - v.y, z - v.z); 43489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 43589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 43689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 43789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** 43889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Maintains running statistics on the signal revelant to AnyMotion detection, including: 43989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * <ul> 44089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * <li>running average. 44189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * <li>running sum-of-squared-errors as the energy of the signal derivative. 44289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * <ul> 44389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 44489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan private static class RunningSignalStats { 44589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Vector3 previousVector; 44689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Vector3 currentVector; 44789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Vector3 runningSum; 44889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan float energy; 44989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan int sampleCount; 45089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 45189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public RunningSignalStats() { 45289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan reset(); 45389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 45489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 45589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public void reset() { 45689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan previousVector = null; 45789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan currentVector = null; 45889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan runningSum = new Vector3(0, 0, 0, 0); 45989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan energy = 0; 46089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan sampleCount = 0; 46189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 46289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 46389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan /** 46489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan * Apply a 3D vector v as the next element in the running SSE. 46589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan */ 46689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public void accumulate(Vector3 v) { 46789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (v == null) { 46889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (DEBUG) Slog.i(TAG, "Cannot accumulate a null vector."); 46989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return; 47089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 47189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan sampleCount++; 47289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan runningSum = runningSum.plus(v); 47389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan previousVector = currentVector; 47489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan currentVector = v; 47589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (previousVector != null) { 47689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan Vector3 dv = currentVector.minus(previousVector); 47789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan float incrementalEnergy = dv.x * dv.x + dv.y * dv.y + dv.z * dv.z; 47889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan energy += incrementalEnergy; 47989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (DEBUG) Slog.i(TAG, "Accumulated vector " + currentVector.toString() + 48089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan ", runningSum = " + runningSum.toString() + 48189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan ", incrementalEnergy = " + incrementalEnergy + 48289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan ", energy = " + energy); 48389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 48489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 48589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 48689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public Vector3 getRunningAverage() { 48789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan if (sampleCount > 0) { 48889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return runningSum.times((float)(1.0f / sampleCount)); 48989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 49089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return null; 49189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 49289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 49389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public float getEnergy() { 49489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return energy; 49589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 49689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 49789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public int getSampleCount() { 49889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return sampleCount; 49989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 50089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan 50189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan @Override 50289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan public String toString() { 50389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan String msg = ""; 50489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan String currentVectorString = (currentVector == null) ? 50589ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan "null" : currentVector.toString(); 50689ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan String previousVectorString = (previousVector == null) ? 50789ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan "null" : previousVector.toString(); 50889ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan msg += "previousVector = " + previousVectorString; 50989ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan msg += ", currentVector = " + currentVectorString; 51089ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan msg += ", sampleCount = " + sampleCount; 51189ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan msg += ", energy = " + energy; 51289ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan return msg; 51389ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 51489ecf82f8ecfe328ef5b7ebf140580c8cad868baKevin Gabayan } 5155e48844381e41c999a7147ec28f075d440177c2dKevin Gabayan} 516