1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.app; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.hardware.Sensor; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.hardware.SensorEvent; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.hardware.SensorEventListener; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.hardware.SensorManager; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.SystemClock; 25fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Changimport android.util.FloatMath; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.Display; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.Surface; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.WindowManager; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 302b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.common.Utils; 312b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.util.GalleryUtils; 322b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class EyePosition { 347817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @SuppressWarnings("unused") 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "EyePosition"; 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public interface EyePositionListener { 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onEyePositionChanged(float x, float y, float z); 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float GYROSCOPE_THRESHOLD = 0.15f; 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float GYROSCOPE_LIMIT = 10f; 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int GYROSCOPE_SETTLE_DOWN = 15; 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float GYROSCOPE_RESTORE_FACTOR = 0.995f; 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 46fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang private static final float USER_ANGEL = (float) Math.toRadians(10); 47fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang private static final float USER_ANGEL_COS = FloatMath.cos(USER_ANGEL); 48fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang private static final float USER_ANGEL_SIN = FloatMath.sin(USER_ANGEL); 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float MAX_VIEW_RANGE = (float) 0.5; 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int NOT_STARTED = -1; 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float USER_DISTANCE_METER = 0.3f; 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Context mContext; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private EyePositionListener mListener; 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Display mDisplay; 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The eyes' position of the user, the origin is at the center of the 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // device and the unit is in pixels. 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private float mX; 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private float mY; 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private float mZ; 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final float mUserDistance; // in pixel 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final float mLimit; 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private long mStartTime = NOT_STARTED; 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Sensor mSensor; 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private PositionListener mPositionListener = new PositionListener(); 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mGyroscopeCountdown = 0; 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public EyePosition(Context context, EyePositionListener listener) { 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContext = context; 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener = listener; 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUserDistance = GalleryUtils.meterToPixel(USER_DISTANCE_METER); 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLimit = mUserDistance * MAX_VIEW_RANGE; 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin WindowManager wManager = (WindowManager) mContext 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin .getSystemService(Context.WINDOW_SERVICE); 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDisplay = wManager.getDefaultDisplay(); 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 81fd06154c0d51fd8686ffec3955e54f5c18e87da0Chih-Chung Chang // The 3D effect where the photo albums fan out in 3D based on angle 82fd06154c0d51fd8686ffec3955e54f5c18e87da0Chih-Chung Chang // of device tilt is currently disabled. 83fd06154c0d51fd8686ffec3955e54f5c18e87da0Chih-Chung Chang/* 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin SensorManager sManager = (SensorManager) mContext 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin .getSystemService(Context.SENSOR_SERVICE); 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSensor = sManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mSensor == null) { 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.w(TAG, "no gyroscope, use accelerometer instead"); 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSensor = sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mSensor == null) { 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.w(TAG, "no sensor available"); 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 94fd06154c0d51fd8686ffec3955e54f5c18e87da0Chih-Chung Chang*/ 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void resetPosition() { 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mStartTime = NOT_STARTED; 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mX = mY = 0; 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mZ = -mUserDistance; 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener.onEyePositionChanged(mX, mY, mZ); 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /* 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * We assume the user is at the following position 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * /|\ user's eye 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | / 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * -G(gravity) | / 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * |_/ 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * / |/_____\ -Y (-y direction of device) 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * user angel 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void onAccelerometerChanged(float gx, float gy, float gz) { 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float x = gx, y = gy, z = gz; 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (mDisplay.getRotation()) { 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case Surface.ROTATION_90: x = -gy; y= gx; break; 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case Surface.ROTATION_180: x = -gx; y = -gy; break; 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case Surface.ROTATION_270: x = gy; y = -gx; break; 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float temp = x * x + y * y + z * z; 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float t = -y /temp; 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float tx = t * x; 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float ty = -1 + t * y; 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float tz = t * z; 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 131fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang float length = FloatMath.sqrt(tx * tx + ty * ty + tz * tz); 132fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang float glength = FloatMath.sqrt(temp); 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mX = Utils.clamp((x * USER_ANGEL_COS / glength 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin + tx * USER_ANGEL_SIN / length) * mUserDistance, 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin -mLimit, mLimit); 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mY = -Utils.clamp((y * USER_ANGEL_COS / glength 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin + ty * USER_ANGEL_SIN / length) * mUserDistance, 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin -mLimit, mLimit); 140fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang mZ = -FloatMath.sqrt( 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUserDistance * mUserDistance - mX * mX - mY * mY); 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener.onEyePositionChanged(mX, mY, mZ); 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void onGyroscopeChanged(float gx, float gy, float gz) { 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long now = SystemClock.elapsedRealtime(); 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float distance = (gx > 0 ? gx : -gx) + (gy > 0 ? gy : - gy); 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (distance < GYROSCOPE_THRESHOLD 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin || distance > GYROSCOPE_LIMIT || mGyroscopeCountdown > 0) { 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin --mGyroscopeCountdown; 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mStartTime = now; 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float limit = mUserDistance / 20f; 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mX > limit || mX < -limit || mY > limit || mY < -limit) { 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mX *= GYROSCOPE_RESTORE_FACTOR; 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mY *= GYROSCOPE_RESTORE_FACTOR; 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mZ = (float) -Math.sqrt( 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUserDistance * mUserDistance - mX * mX - mY * mY); 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener.onEyePositionChanged(mX, mY, mZ); 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float t = (now - mStartTime) / 1000f * mUserDistance * (-mZ); 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mStartTime = now; 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float x = -gy, y = -gx; 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (mDisplay.getRotation()) { 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case Surface.ROTATION_90: x = -gx; y= gy; break; 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case Surface.ROTATION_180: x = gy; y = gx; break; 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case Surface.ROTATION_270: x = gx; y = -gy; break; 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mX = Utils.clamp((float) (mX + x * t / Math.hypot(mZ, mX)), 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin -mLimit, mLimit) * GYROSCOPE_RESTORE_FACTOR; 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mY = Utils.clamp((float) (mY + y * t / Math.hypot(mZ, mY)), 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin -mLimit, mLimit) * GYROSCOPE_RESTORE_FACTOR; 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 178fd91413ab46e2960803a33652025aebe3e05f2d9Chih-Chung Chang mZ = -FloatMath.sqrt( 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUserDistance * mUserDistance - mX * mX - mY * mY); 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener.onEyePositionChanged(mX, mY, mZ); 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class PositionListener implements SensorEventListener { 1847817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onAccuracyChanged(Sensor sensor, int accuracy) { 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1887817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onSensorChanged(SensorEvent event) { 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (event.sensor.getType()) { 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case Sensor.TYPE_GYROSCOPE: { 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin onGyroscopeChanged( 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin event.values[0], event.values[1], event.values[2]); 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case Sensor.TYPE_ACCELEROMETER: { 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin onAccelerometerChanged( 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin event.values[0], event.values[1], event.values[2]); 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void pause() { 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mSensor != null) { 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin SensorManager sManager = (SensorManager) mContext 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin .getSystemService(Context.SENSOR_SERVICE); 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sManager.unregisterListener(mPositionListener); 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void resume() { 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mSensor != null) { 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin SensorManager sManager = (SensorManager) mContext 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin .getSystemService(Context.SENSOR_SERVICE); 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sManager.registerListener(mPositionListener, 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSensor, SensorManager.SENSOR_DELAY_GAME); 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mStartTime = NOT_STARTED; 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mGyroscopeCountdown = GYROSCOPE_SETTLE_DOWN; 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mX = mY = 0; 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mZ = -mUserDistance; 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener.onEyePositionChanged(mX, mY, mZ); 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 227