1 /* 2 * Copyright (C) 2010 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 17 package android.webkit; 18 19 import android.content.Context; 20 import android.hardware.Sensor; 21 import android.hardware.SensorEvent; 22 import android.hardware.SensorEventListener; 23 import android.hardware.SensorManager; 24 import android.os.Handler; 25 import android.os.Message; 26 import android.webkit.DeviceMotionAndOrientationManager; 27 import java.lang.Runnable; 28 import java.util.List; 29 30 31 final class DeviceMotionService implements SensorEventListener { 32 private DeviceMotionAndOrientationManager mManager; 33 private boolean mIsRunning; 34 private Handler mHandler; 35 private SensorManager mSensorManager; 36 private Context mContext; 37 private boolean mHaveSentErrorEvent; 38 private Runnable mUpdateRunnable; 39 private float mLastAcceleration[]; 40 41 private static final int INTERVAL_MILLIS = 100; 42 43 public DeviceMotionService(DeviceMotionAndOrientationManager manager, Context context) { 44 mManager = manager; 45 assert(mManager != null); 46 mContext = context; 47 assert(mContext != null); 48 } 49 50 public void start() { 51 mIsRunning = true; 52 registerForSensor(); 53 } 54 55 public void stop() { 56 mIsRunning = false; 57 stopSendingUpdates(); 58 unregisterFromSensor(); 59 } 60 61 public void suspend() { 62 if (mIsRunning) { 63 stopSendingUpdates(); 64 unregisterFromSensor(); 65 } 66 } 67 68 public void resume() { 69 if (mIsRunning) { 70 registerForSensor(); 71 } 72 } 73 74 private void sendErrorEvent() { 75 assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 76 // The spec requires that each listener receives the error event only once. 77 if (mHaveSentErrorEvent) 78 return; 79 mHaveSentErrorEvent = true; 80 createHandler(); 81 mHandler.post(new Runnable() { 82 @Override 83 public void run() { 84 assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 85 if (mIsRunning) { 86 // The special case of all nulls is used to signify a failure to get data. 87 mManager.onMotionChange(null, null, null, 0.0); 88 } 89 } 90 }); 91 } 92 93 private void createHandler() { 94 if (mHandler != null) { 95 return; 96 } 97 98 mHandler = new Handler(); 99 mUpdateRunnable = new Runnable() { 100 @Override 101 public void run() { 102 assert mIsRunning; 103 mManager.onMotionChange(new Double(mLastAcceleration[0]), 104 new Double(mLastAcceleration[1]), new Double(mLastAcceleration[2]), 105 INTERVAL_MILLIS); 106 mHandler.postDelayed(mUpdateRunnable, INTERVAL_MILLIS); 107 // Now that we have successfully sent some data, reset whether we've sent an error. 108 mHaveSentErrorEvent = false; 109 } 110 }; 111 } 112 113 private void startSendingUpdates() { 114 createHandler(); 115 mUpdateRunnable.run(); 116 } 117 118 private void stopSendingUpdates() { 119 mHandler.removeCallbacks(mUpdateRunnable); 120 mLastAcceleration = null; 121 } 122 123 private void registerForSensor() { 124 if (!registerForAccelerometerSensor()) { 125 sendErrorEvent(); 126 } 127 } 128 129 private SensorManager getSensorManager() { 130 assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 131 if (mSensorManager == null) { 132 mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); 133 } 134 return mSensorManager; 135 } 136 137 private boolean registerForAccelerometerSensor() { 138 List<Sensor> sensors = getSensorManager().getSensorList(Sensor.TYPE_ACCELEROMETER); 139 if (sensors.isEmpty()) { 140 return false; 141 } 142 createHandler(); 143 // TODO: Consider handling multiple sensors. 144 return getSensorManager().registerListener( 145 this, sensors.get(0), SensorManager.SENSOR_DELAY_UI, mHandler); 146 } 147 148 private void unregisterFromSensor() { 149 getSensorManager().unregisterListener(this); 150 } 151 152 /** 153 * SensorEventListener implementation. 154 * Callbacks happen on the thread on which we registered - the WebCore thread. 155 */ 156 public void onSensorChanged(SensorEvent event) { 157 assert(event.values.length == 3); 158 assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 159 assert(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER); 160 161 // We may get callbacks after the call to getSensorManager().unregisterListener() returns. 162 if (!mIsRunning) { 163 return; 164 } 165 166 boolean firstData = mLastAcceleration == null; 167 mLastAcceleration = event.values; 168 if (firstData) { 169 startSendingUpdates(); 170 } 171 } 172 173 public void onAccuracyChanged(Sensor sensor, int accuracy) { 174 assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName()); 175 } 176 } 177