1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.devcamera; 17 18 import android.hardware.Sensor; 19 import android.hardware.SensorEvent; 20 import android.hardware.SensorEventListener; 21 import android.hardware.SensorManager; 22 import android.util.Log; 23 24 import java.util.ArrayDeque; 25 26 /** 27 * Put all the Gyro stuff here. 28 */ 29 public class GyroOperations { 30 private static final String TAG = "DevCamera_GYRO"; 31 32 private SensorManager mSensorManager; 33 private GyroListener mListener; 34 35 private SensorEventListener mSensorEventListener = new SensorEventListener() { 36 @Override 37 public void onSensorChanged(SensorEvent event) { 38 delayGyroData(event); 39 } 40 @Override 41 public void onAccuracyChanged(Sensor sensor, int accuracy) { 42 } 43 }; 44 GyroOperations(SensorManager sensorManager)45 public GyroOperations(SensorManager sensorManager) { 46 mSensorManager = sensorManager; 47 } 48 startListening(GyroListener listener)49 public void startListening(GyroListener listener) { 50 mSensorManager.registerListener(mSensorEventListener, mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_FASTEST); 51 mListener = listener; 52 } 53 stopListening()54 public void stopListening() { 55 mSensorManager.unregisterListener(mSensorEventListener); 56 } 57 58 // We need to make a copy of SensorEvent so we can put it in our delay-line. 59 class GyroEvent2D { 60 public long timestamp; 61 public final float[] values = new float[2]; 62 GyroEvent2D(SensorEvent event)63 public GyroEvent2D(SensorEvent event) { 64 this.timestamp = event.timestamp; 65 this.values[0] = event.values[0]; 66 this.values[1] = event.values[1]; 67 } 68 } 69 70 private long mGyroLastTimestamp = 0; 71 private float[] mGyroAngle = new float[]{0f, 0f}; // radians, X and Y axes. 72 // Gyro arrives at 230 Hz on N6: 23 samples in 100 ms. Viewfinder latency is 70 ms. Delay about 15 samples. 73 private ArrayDeque<GyroEvent2D> mSensorDelayLine = new ArrayDeque<>(); 74 private static final int DELAY_SIZE = 10; 75 delayGyroData(SensorEvent event)76 void delayGyroData(SensorEvent event) { 77 mSensorDelayLine.addLast(new GyroEvent2D(event)); 78 if (mSensorDelayLine.size() < DELAY_SIZE) { 79 return; 80 } 81 GyroEvent2D delayedEvent = mSensorDelayLine.removeFirst(); 82 integrateGyroForPosition(delayedEvent); 83 } 84 integrateGyroForPosition(GyroEvent2D event)85 void integrateGyroForPosition(GyroEvent2D event) { 86 if (mGyroLastTimestamp == 0) { 87 mGyroLastTimestamp = event.timestamp; 88 return; 89 } 90 long dt = (event.timestamp - mGyroLastTimestamp) / 1000; // microseconds between samples 91 if (dt > 10000) { // below 100 Hz 92 Log.v(TAG, " ===============> GYRO STALL <=============="); 93 } 94 mGyroAngle[0] += event.values[0] * 0.000001f * dt; 95 mGyroAngle[1] += event.values[1] * 0.000001f * dt; 96 mGyroLastTimestamp = event.timestamp; 97 98 // TODO: Add UI 99 //updateOrientationUI(mGyroAngle, dt); 100 //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)); 101 102 mListener.updateGyroAngles(mGyroAngle); 103 } 104 105 } 106