| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * 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 com.android.devcamera; |
| |
| import android.hardware.Sensor; |
| import android.hardware.SensorEvent; |
| import android.hardware.SensorEventListener; |
| import android.hardware.SensorManager; |
| import android.util.Log; |
| |
| import java.util.ArrayDeque; |
| |
| /** |
| * Put all the Gyro stuff here. |
| */ |
| public class GyroOperations { |
| private static final String TAG = "DevCamera_GYRO"; |
| |
| private SensorManager mSensorManager; |
| private GyroListener mListener; |
| |
| private SensorEventListener mSensorEventListener = new SensorEventListener() { |
| @Override |
| public void onSensorChanged(SensorEvent event) { |
| delayGyroData(event); |
| } |
| @Override |
| public void onAccuracyChanged(Sensor sensor, int accuracy) { |
| } |
| }; |
| |
| public GyroOperations(SensorManager sensorManager) { |
| mSensorManager = sensorManager; |
| } |
| |
| public void startListening(GyroListener listener) { |
| mSensorManager.registerListener(mSensorEventListener, mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_FASTEST); |
| mListener = listener; |
| } |
| |
| public void stopListening() { |
| mSensorManager.unregisterListener(mSensorEventListener); |
| } |
| |
| // We need to make a copy of SensorEvent so we can put it in our delay-line. |
| class GyroEvent2D { |
| public long timestamp; |
| public final float[] values = new float[2]; |
| |
| public GyroEvent2D(SensorEvent event) { |
| this.timestamp = event.timestamp; |
| this.values[0] = event.values[0]; |
| this.values[1] = event.values[1]; |
| } |
| } |
| |
| private long mGyroLastTimestamp = 0; |
| private float[] mGyroAngle = new float[]{0f, 0f}; // radians, X and Y axes. |
| // Gyro arrives at 230 Hz on N6: 23 samples in 100 ms. Viewfinder latency is 70 ms. Delay about 15 samples. |
| private ArrayDeque<GyroEvent2D> mSensorDelayLine = new ArrayDeque<>(); |
| private static final int DELAY_SIZE = 10; |
| |
| void delayGyroData(SensorEvent event) { |
| mSensorDelayLine.addLast(new GyroEvent2D(event)); |
| if (mSensorDelayLine.size() < DELAY_SIZE) { |
| return; |
| } |
| GyroEvent2D delayedEvent = mSensorDelayLine.removeFirst(); |
| integrateGyroForPosition(delayedEvent); |
| } |
| |
| void integrateGyroForPosition(GyroEvent2D event) { |
| if (mGyroLastTimestamp == 0) { |
| mGyroLastTimestamp = event.timestamp; |
| return; |
| } |
| long dt = (event.timestamp - mGyroLastTimestamp) / 1000; // microseconds between samples |
| if (dt > 10000) { // below 100 Hz |
| Log.v(TAG, " ===============> GYRO STALL <=============="); |
| } |
| mGyroAngle[0] += event.values[0] * 0.000001f * dt; |
| mGyroAngle[1] += event.values[1] * 0.000001f * dt; |
| mGyroLastTimestamp = event.timestamp; |
| |
| // TODO: Add UI |
| //updateOrientationUI(mGyroAngle, dt); |
| //Log.v(TAG, String.format("Gyro: theta_x = %.2f theta_y = %.2f dt = %d", mGyroAngle[0]*180f/3.14f, mGyroAngle[1]*180f/3.14f, dt)); |
| |
| mListener.updateGyroAngles(mGyroAngle); |
| } |
| |
| } |