1c43565be90a3119da675571238de20583ca32400Steve Block/* 2c43565be90a3119da675571238de20583ca32400Steve Block * Copyright (C) 2010 The Android Open Source Project 3c43565be90a3119da675571238de20583ca32400Steve Block * 4c43565be90a3119da675571238de20583ca32400Steve Block * Licensed under the Apache License, Version 2.0 (the "License"); 5c43565be90a3119da675571238de20583ca32400Steve Block * you may not use this file except in compliance with the License. 6c43565be90a3119da675571238de20583ca32400Steve Block * You may obtain a copy of the License at 7c43565be90a3119da675571238de20583ca32400Steve Block * 8c43565be90a3119da675571238de20583ca32400Steve Block * http://www.apache.org/licenses/LICENSE-2.0 9c43565be90a3119da675571238de20583ca32400Steve Block * 10c43565be90a3119da675571238de20583ca32400Steve Block * Unless required by applicable law or agreed to in writing, software 11c43565be90a3119da675571238de20583ca32400Steve Block * distributed under the License is distributed on an "AS IS" BASIS, 12c43565be90a3119da675571238de20583ca32400Steve Block * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c43565be90a3119da675571238de20583ca32400Steve Block * See the License for the specific language governing permissions and 14c43565be90a3119da675571238de20583ca32400Steve Block * limitations under the License. 15c43565be90a3119da675571238de20583ca32400Steve Block */ 16c43565be90a3119da675571238de20583ca32400Steve Block 17c43565be90a3119da675571238de20583ca32400Steve Blockpackage android.webkit; 18c43565be90a3119da675571238de20583ca32400Steve Block 19bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Blockimport android.content.Context; 20bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Blockimport android.hardware.Sensor; 21bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Blockimport android.hardware.SensorEvent; 22bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Blockimport android.hardware.SensorEventListener; 23bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Blockimport android.hardware.SensorManager; 24c43565be90a3119da675571238de20583ca32400Steve Blockimport android.os.Handler; 251be73390778eb1b033a4db6339c8a8b325dfaad9Steve Blockimport android.webkit.DeviceMotionAndOrientationManager; 26c43565be90a3119da675571238de20583ca32400Steve Blockimport java.lang.Runnable; 27bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Blockimport java.util.List; 28c43565be90a3119da675571238de20583ca32400Steve Block 29c43565be90a3119da675571238de20583ca32400Steve Block 30bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Blockfinal class DeviceOrientationService implements SensorEventListener { 31bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // The gravity vector expressed in the body frame. 32bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private float[] mGravityVector; 33bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // The geomagnetic vector expressed in the body frame. 34bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private float[] mMagneticFieldVector; 35bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 361be73390778eb1b033a4db6339c8a8b325dfaad9Steve Block private DeviceMotionAndOrientationManager mManager; 37c43565be90a3119da675571238de20583ca32400Steve Block private boolean mIsRunning; 38c43565be90a3119da675571238de20583ca32400Steve Block private Handler mHandler; 39bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private SensorManager mSensorManager; 40bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private Context mContext; 41bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private Double mAlpha; 42bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private Double mBeta; 43bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private Double mGamma; 448980343b13137aba5bd11d0d961360c03689d434Steve Block private boolean mHaveSentErrorEvent; 45bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 46bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private static final double DELTA_DEGRESS = 1.0; 47c43565be90a3119da675571238de20583ca32400Steve Block 481be73390778eb1b033a4db6339c8a8b325dfaad9Steve Block public DeviceOrientationService(DeviceMotionAndOrientationManager manager, Context context) { 49c43565be90a3119da675571238de20583ca32400Steve Block mManager = manager; 50c43565be90a3119da675571238de20583ca32400Steve Block assert(mManager != null); 51bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mContext = context; 52bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block assert(mContext != null); 53c43565be90a3119da675571238de20583ca32400Steve Block } 54c43565be90a3119da675571238de20583ca32400Steve Block 55c43565be90a3119da675571238de20583ca32400Steve Block public void start() { 56c43565be90a3119da675571238de20583ca32400Steve Block mIsRunning = true; 57c43565be90a3119da675571238de20583ca32400Steve Block registerForSensors(); 58c43565be90a3119da675571238de20583ca32400Steve Block } 59c43565be90a3119da675571238de20583ca32400Steve Block 60c43565be90a3119da675571238de20583ca32400Steve Block public void stop() { 61c43565be90a3119da675571238de20583ca32400Steve Block mIsRunning = false; 62c43565be90a3119da675571238de20583ca32400Steve Block unregisterFromSensors(); 63c43565be90a3119da675571238de20583ca32400Steve Block } 64c43565be90a3119da675571238de20583ca32400Steve Block 65c43565be90a3119da675571238de20583ca32400Steve Block public void suspend() { 66c43565be90a3119da675571238de20583ca32400Steve Block if (mIsRunning) { 67c43565be90a3119da675571238de20583ca32400Steve Block unregisterFromSensors(); 68c43565be90a3119da675571238de20583ca32400Steve Block } 69c43565be90a3119da675571238de20583ca32400Steve Block } 70c43565be90a3119da675571238de20583ca32400Steve Block 71c43565be90a3119da675571238de20583ca32400Steve Block public void resume() { 72c43565be90a3119da675571238de20583ca32400Steve Block if (mIsRunning) { 73c43565be90a3119da675571238de20583ca32400Steve Block registerForSensors(); 74c43565be90a3119da675571238de20583ca32400Steve Block } 75c43565be90a3119da675571238de20583ca32400Steve Block } 76c43565be90a3119da675571238de20583ca32400Steve Block 77c43565be90a3119da675571238de20583ca32400Steve Block private void sendErrorEvent() { 78c43565be90a3119da675571238de20583ca32400Steve Block assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 798980343b13137aba5bd11d0d961360c03689d434Steve Block // The spec requires that each listener receives the error event only once. 808980343b13137aba5bd11d0d961360c03689d434Steve Block if (mHaveSentErrorEvent) 818980343b13137aba5bd11d0d961360c03689d434Steve Block return; 828980343b13137aba5bd11d0d961360c03689d434Steve Block mHaveSentErrorEvent = true; 83c43565be90a3119da675571238de20583ca32400Steve Block mHandler.post(new Runnable() { 84c43565be90a3119da675571238de20583ca32400Steve Block @Override 85c43565be90a3119da675571238de20583ca32400Steve Block public void run() { 86c43565be90a3119da675571238de20583ca32400Steve Block assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 87c43565be90a3119da675571238de20583ca32400Steve Block if (mIsRunning) { 888980343b13137aba5bd11d0d961360c03689d434Steve Block // The special case of all nulls is used to signify a failure to get data. 89c43565be90a3119da675571238de20583ca32400Steve Block mManager.onOrientationChange(null, null, null); 90c43565be90a3119da675571238de20583ca32400Steve Block } 91c43565be90a3119da675571238de20583ca32400Steve Block } 92c43565be90a3119da675571238de20583ca32400Steve Block }); 93c43565be90a3119da675571238de20583ca32400Steve Block } 94c43565be90a3119da675571238de20583ca32400Steve Block 95c43565be90a3119da675571238de20583ca32400Steve Block private void registerForSensors() { 96bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (mHandler == null) { 97bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mHandler = new Handler(); 98bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 99bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (!registerForAccelerometerSensor() || !registerForMagneticFieldSensor()) { 100bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block unregisterFromSensors(); 101bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block sendErrorEvent(); 102bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 103bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 104bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 105bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private void getOrientationUsingGetRotationMatrix() { 106bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (mGravityVector == null || mMagneticFieldVector == null) { 107bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block return; 108bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 109bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 110bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // Get the rotation matrix. 111bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // The rotation matrix that transforms from the body frame to the earth frame. 112bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block float[] deviceRotationMatrix = new float[9]; 113bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (!SensorManager.getRotationMatrix( 114bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block deviceRotationMatrix, null, mGravityVector, mMagneticFieldVector)) { 115bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block return; 116bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 117bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 118bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // Convert rotation matrix to rotation angles. 119bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // Assuming that the rotations are appied in the order listed at 120bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // http://developer.android.com/reference/android/hardware/SensorEvent.html#values 121bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // the rotations are applied about the same axes and in the same order as required by the 122bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // API. The only conversions are sign changes as follows. 123bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // The angles are in radians 124bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block float[] rotationAngles = new float[3]; 125bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block SensorManager.getOrientation(deviceRotationMatrix, rotationAngles); 126d5be055f79615e2b80fb3fe92a35db2bc84c023dSteve Block double alpha = Math.toDegrees(-rotationAngles[0]); 127bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block while (alpha < 0.0) { alpha += 360.0; } // [0, 360) 128bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block double beta = Math.toDegrees(-rotationAngles[1]); 129bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block while (beta < -180.0) { beta += 360.0; } // [-180, 180) 130bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block double gamma = Math.toDegrees(rotationAngles[2]); 131bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block while (gamma < -90.0) { gamma += 360.0; } // [-90, 90) 132bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 133bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block maybeSendChange(alpha, beta, gamma); 134bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 135bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 136bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private SensorManager getSensorManager() { 137bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 138bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (mSensorManager == null) { 139bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); 140bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 141bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block return mSensorManager; 142bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 143bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 144bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private boolean registerForAccelerometerSensor() { 145bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block List<Sensor> sensors = getSensorManager().getSensorList(Sensor.TYPE_ACCELEROMETER); 146bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (sensors.isEmpty()) { 147bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block return false; 148bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 149bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // TODO: Consider handling multiple sensors. 150bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block return getSensorManager().registerListener( 151bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block this, sensors.get(0), SensorManager.SENSOR_DELAY_FASTEST, mHandler); 152bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 153bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 154bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private boolean registerForMagneticFieldSensor() { 155bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block List<Sensor> sensors = getSensorManager().getSensorList(Sensor.TYPE_MAGNETIC_FIELD); 156bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (sensors.isEmpty()) { 157bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block return false; 158bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 159bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block // TODO: Consider handling multiple sensors. 160bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block return getSensorManager().registerListener( 161bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block this, sensors.get(0), SensorManager.SENSOR_DELAY_FASTEST, mHandler); 162c43565be90a3119da675571238de20583ca32400Steve Block } 163c43565be90a3119da675571238de20583ca32400Steve Block 164c43565be90a3119da675571238de20583ca32400Steve Block private void unregisterFromSensors() { 165bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block getSensorManager().unregisterListener(this); 166bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 167bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 168bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block private void maybeSendChange(double alpha, double beta, double gamma) { 169bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 170bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (mAlpha == null || mBeta == null || mGamma == null 171bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block || Math.abs(alpha - mAlpha) > DELTA_DEGRESS 172bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block || Math.abs(beta - mBeta) > DELTA_DEGRESS 173bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block || Math.abs(gamma - mGamma) > DELTA_DEGRESS) { 174bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mAlpha = alpha; 175bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mBeta = beta; 176bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mGamma = gamma; 177bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mManager.onOrientationChange(mAlpha, mBeta, mGamma); 1788980343b13137aba5bd11d0d961360c03689d434Steve Block // Now that we have successfully sent some data, reset whether we've sent an error. 1798980343b13137aba5bd11d0d961360c03689d434Steve Block mHaveSentErrorEvent = false; 180bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 181bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 182bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 183bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block /** 184bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block * SensorEventListener implementation. 185bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block * Callbacks happen on the thread on which we registered - the WebCore thread. 186bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block */ 1875ba2efeb9faaf7db9da205102b9a7f40b4b89f27Steve Block @Override 188bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block public void onSensorChanged(SensorEvent event) { 189bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block assert(event.values.length == 3); 190bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 191bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 192d09001fea476ca6c6eaff5e29a1bb6f3aebe5bd5Steve Block // We may get callbacks after the call to getSensorManager().unregisterListener() returns. 193bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (!mIsRunning) { 194bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block return; 195bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 196bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 197bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block switch (event.sensor.getType()) { 198bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block case Sensor.TYPE_ACCELEROMETER: 199bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (mGravityVector == null) { 200bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mGravityVector = new float[3]; 201bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 202bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mGravityVector[0] = event.values[0]; 203bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mGravityVector[1] = event.values[1]; 204bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mGravityVector[2] = event.values[2]; 205bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block getOrientationUsingGetRotationMatrix(); 206bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block break; 207bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block case Sensor.TYPE_MAGNETIC_FIELD: 208bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block if (mMagneticFieldVector == null) { 209bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mMagneticFieldVector = new float[3]; 210bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 211bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mMagneticFieldVector[0] = event.values[0]; 212bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mMagneticFieldVector[1] = event.values[1]; 213bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block mMagneticFieldVector[2] = event.values[2]; 214bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block getOrientationUsingGetRotationMatrix(); 215bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block break; 216bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block default: 217bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block assert(false); 218bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 219bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block } 220bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block 2215ba2efeb9faaf7db9da205102b9a7f40b4b89f27Steve Block @Override 222bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block public void onAccuracyChanged(Sensor sensor, int accuracy) { 223bb9db22fbb264f9a31ab85f74339b94cb1ab7151Steve Block assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 224c43565be90a3119da675571238de20583ca32400Steve Block } 225c43565be90a3119da675571238de20583ca32400Steve Block} 226