// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.google.vrtoolkit.cardboard.sensors; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.opengl.Matrix; import android.view.Display; import android.view.WindowManager; import com.google.vrtoolkit.cardboard.sensors.internal.GyroscopeBiasEstimator; import com.google.vrtoolkit.cardboard.sensors.internal.Matrix3x3d; import com.google.vrtoolkit.cardboard.sensors.internal.OrientationEKF; import com.google.vrtoolkit.cardboard.sensors.internal.Vector3d; import java.util.concurrent.TimeUnit; public class HeadTracker implements SensorEventListener { private static final float DEFAULT_NECK_HORIZONTAL_OFFSET = 0.08F; private static final float DEFAULT_NECK_VERTICAL_OFFSET = 0.075F; private static final float DEFAULT_NECK_MODEL_FACTOR = 1.0F; private static final float PREDICTION_TIME_IN_SECONDS = 0.058F; private final Display display; private final float[] ekfToHeadTracker = new float[16]; private final float[] sensorToDisplay = new float[16]; private float displayRotation = -1.0F; private final float[] neckModelTranslation = new float[16]; private final float[] tmpHeadView = new float[16]; private final float[] tmpHeadView2 = new float[16]; private float neckModelFactor = 1.0F; private final Object neckModelFactorMutex = new Object(); private volatile boolean tracking; private final OrientationEKF tracker; private final Object gyroBiasEstimatorMutex = new Object(); private GyroscopeBiasEstimator gyroBiasEstimator; private SensorEventProvider sensorEventProvider; private Clock clock; private long latestGyroEventClockTimeNs; private volatile boolean firstGyroValue = true; private float[] initialSystemGyroBias = new float[3]; private final Vector3d gyroBias = new Vector3d(); private final Vector3d latestGyro = new Vector3d(); private final Vector3d latestAcc = new Vector3d(); public static HeadTracker createFromContext(Context context) { SensorManager sensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); Display display = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); return new HeadTracker(new DeviceSensorLooper(sensorManager), new SystemClock(), display); } public HeadTracker(SensorEventProvider sensorEventProvider, Clock clock, Display display) { this.clock = clock; this.sensorEventProvider = sensorEventProvider; this.tracker = new OrientationEKF(); this.display = display; this.setGyroBiasEstimationEnabled(true); Matrix.setIdentityM(this.neckModelTranslation, 0); } public void onSensorChanged(SensorEvent event) { Object var2; if(event.sensor.getType() == 1) { this.latestAcc.set((double)event.values[0], (double)event.values[1], (double)event.values[2]); this.tracker.processAcc(this.latestAcc, event.timestamp); var2 = this.gyroBiasEstimatorMutex; synchronized(this.gyroBiasEstimatorMutex) { if(this.gyroBiasEstimator != null) { this.gyroBiasEstimator.processAccelerometer(this.latestAcc, event.timestamp); } } } else if(event.sensor.getType() == 4 || event.sensor.getType() == 16) { this.latestGyroEventClockTimeNs = this.clock.nanoTime(); if(event.sensor.getType() == 16) { if(this.firstGyroValue && event.values.length == 6) { this.initialSystemGyroBias[0] = event.values[3]; this.initialSystemGyroBias[1] = event.values[4]; this.initialSystemGyroBias[2] = event.values[5]; } this.latestGyro.set((double)(event.values[0] - this.initialSystemGyroBias[0]), (double)(event.values[1] - this.initialSystemGyroBias[1]), (double)(event.values[2] - this.initialSystemGyroBias[2])); } else { this.latestGyro.set((double)event.values[0], (double)event.values[1], (double)event.values[2]); } this.firstGyroValue = false; var2 = this.gyroBiasEstimatorMutex; synchronized(this.gyroBiasEstimatorMutex) { if(this.gyroBiasEstimator != null) { this.gyroBiasEstimator.processGyroscope(this.latestGyro, event.timestamp); this.gyroBiasEstimator.getGyroBias(this.gyroBias); Vector3d.sub(this.latestGyro, this.gyroBias, this.latestGyro); } } this.tracker.processGyro(this.latestGyro, event.timestamp); } } public void onAccuracyChanged(Sensor sensor, int accuracy) { } public void startTracking() { if(!this.tracking) { this.tracker.reset(); Object var1 = this.gyroBiasEstimatorMutex; synchronized(this.gyroBiasEstimatorMutex) { if(this.gyroBiasEstimator != null) { this.gyroBiasEstimator.reset(); } } this.firstGyroValue = true; this.sensorEventProvider.registerListener(this); this.sensorEventProvider.start(); this.tracking = true; } } public void resetTracker() { this.tracker.reset(); } public void stopTracking() { if(this.tracking) { this.sensorEventProvider.unregisterListener(this); this.sensorEventProvider.stop(); this.tracking = false; } } public void setNeckModelEnabled(boolean enabled) { if(enabled) { this.setNeckModelFactor(1.0F); } else { this.setNeckModelFactor(0.0F); } } public float getNeckModelFactor() { Object var1 = this.neckModelFactorMutex; synchronized(this.neckModelFactorMutex) { return this.neckModelFactor; } } public void setNeckModelFactor(float factor) { Object var2 = this.neckModelFactorMutex; synchronized(this.neckModelFactorMutex) { if(factor >= 0.0F && factor <= 1.0F) { this.neckModelFactor = factor; } else { throw new IllegalArgumentException("factor should be within [0.0, 1.0]"); } } } public void setGyroBiasEstimationEnabled(boolean enabled) { Object var2 = this.gyroBiasEstimatorMutex; synchronized(this.gyroBiasEstimatorMutex) { if(!enabled) { this.gyroBiasEstimator = null; } else if(this.gyroBiasEstimator == null) { this.gyroBiasEstimator = new GyroscopeBiasEstimator(); } } } public boolean getGyroBiasEstimationEnabled() { Object var1 = this.gyroBiasEstimatorMutex; synchronized(this.gyroBiasEstimatorMutex) { return this.gyroBiasEstimator != null; } } public void getLastHeadView(float[] headView, int offset) { if(offset + 16 > headView.length) { throw new IllegalArgumentException("Not enough space to write the result"); } else { float rotation = 0.0F; switch(this.display.getRotation()) { case 0: rotation = 0.0F; break; case 1: rotation = 90.0F; break; case 2: rotation = 180.0F; break; case 3: rotation = 270.0F; } if(rotation != this.displayRotation) { this.displayRotation = rotation; Matrix.setRotateEulerM(this.sensorToDisplay, 0, 0.0F, 0.0F, -rotation); Matrix.setRotateEulerM(this.ekfToHeadTracker, 0, -90.0F, 0.0F, rotation); } OrientationEKF var4 = this.tracker; synchronized(this.tracker) { if(!this.tracker.isReady()) { return; } double secondsSinceLastGyroEvent = (double)TimeUnit.NANOSECONDS.toSeconds(this.clock.nanoTime() - this.latestGyroEventClockTimeNs); double secondsToPredictForward = secondsSinceLastGyroEvent + 0.057999998331069946D; double[] mat = this.tracker.getPredictedGLMatrix(secondsToPredictForward); int i = 0; while(true) { if(i >= headView.length) { break; } this.tmpHeadView[i] = (float)mat[i]; ++i; } } Matrix.multiplyMM(this.tmpHeadView2, 0, this.sensorToDisplay, 0, this.tmpHeadView, 0); Matrix.multiplyMM(headView, offset, this.tmpHeadView2, 0, this.ekfToHeadTracker, 0); Matrix.setIdentityM(this.neckModelTranslation, 0); Matrix.translateM(this.neckModelTranslation, 0, 0.0F, -this.neckModelFactor * 0.075F, this.neckModelFactor * 0.08F); Matrix.multiplyMM(this.tmpHeadView, 0, this.neckModelTranslation, 0, headView, offset); Matrix.translateM(headView, offset, this.tmpHeadView, 0, 0.0F, this.neckModelFactor * 0.075F, 0.0F); } } Matrix3x3d getCurrentPoseForTest() { return new Matrix3x3d(this.tracker.getRotationMatrix()); } void setGyroBiasEstimator(GyroscopeBiasEstimator estimator) { Object var2 = this.gyroBiasEstimatorMutex; synchronized(this.gyroBiasEstimatorMutex) { this.gyroBiasEstimator = estimator; } } }