Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(868)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/DeviceOrientation.java

Issue 12771008: Implement java-side browser sensor polling for device motion and device orientation DOM events. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed Marcus's comments Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.content.browser;
6
7 import android.content.Context;
8 import android.hardware.Sensor;
9 import android.hardware.SensorEvent;
10 import android.hardware.SensorEventListener;
11 import android.hardware.SensorManager;
12 import android.os.Handler;
13 import android.os.Looper;
14
15 import org.chromium.base.CalledByNative;
16 import org.chromium.base.JNINamespace;
17 import org.chromium.base.WeakContext;
18
19 import java.util.List;
20
21 /**
22 * Android implementation of the DeviceOrientation API.
23 */
24 @JNINamespace("content")
25 class DeviceOrientation implements SensorEventListener {
26
27 // These fields are lazily initialized by getHandler().
28 private Thread mThread;
29 private Handler mHandler;
30
31 // The lock to access the mHandler.
32 private Object mHandlerLock = new Object();
33
34 // Non-zero if and only if we're listening for events.
35 // To avoid race conditions on the C++ side, access must be synchronized.
36 private int mNativePtr;
37
38 // The lock to access the mNativePtr.
39 private Object mNativePtrLock = new Object();
40
41 // The gravity vector expressed in the body frame.
42 private float[] mGravityVector;
43
44 // The geomagnetic vector expressed in the body frame.
45 private float[] mMagneticFieldVector;
46
47 // Lazily initialized when registering for notifications.
48 private SensorManager mSensorManager;
49
50 // The only instance of that class and its associated lock.
51 private static DeviceOrientation sSingleton;
52 private static Object sSingletonLock = new Object();
53
54 private DeviceOrientation() {
55 }
56
57 /**
58 * Start listening for sensor events. If this object is already listening
59 * for events, the old callback is unregistered first.
60 *
61 * @param nativePtr Value to pass to nativeGotOrientation() for each event.
62 * @param rateInMilliseconds Requested callback rate in milliseconds. The
63 * actual rate may be higher. Unwanted events should be ignored.
64 * @return True on success.
65 */
66 @CalledByNative
67 public boolean start(int nativePtr, int rateInMilliseconds) {
68 synchronized (mNativePtrLock) {
69 stop();
70 if (registerForSensors(rateInMilliseconds)) {
71 mNativePtr = nativePtr;
72 return true;
73 }
74 return false;
75 }
76 }
77
78 /**
79 * Stop listening for sensor events. Always succeeds.
80 *
81 * We strictly guarantee that nativeGotOrientation() will not be called
82 * after this method returns.
83 */
84 @CalledByNative
85 public void stop() {
86 synchronized (mNativePtrLock) {
87 if (mNativePtr != 0) {
88 mNativePtr = 0;
89 unregisterForSensors();
90 }
91 }
92 }
93
94 @Override
95 public void onAccuracyChanged(Sensor sensor, int accuracy) {
96 // Nothing
97 }
98
99 @Override
100 public void onSensorChanged(SensorEvent event) {
101 switch (event.sensor.getType()) {
102 case Sensor.TYPE_ACCELEROMETER:
103 if (mGravityVector == null) {
104 mGravityVector = new float[3];
105 }
106 System.arraycopy(event.values, 0, mGravityVector, 0, mGravityVec tor.length);
107 break;
108
109 case Sensor.TYPE_MAGNETIC_FIELD:
110 if (mMagneticFieldVector == null) {
111 mMagneticFieldVector = new float[3];
112 }
113 System.arraycopy(event.values, 0, mMagneticFieldVector, 0,
114 mMagneticFieldVector.length);
115 break;
116
117 default:
118 // Unexpected
119 return;
120 }
121
122 getOrientationUsingGetRotationMatrix();
123 }
124
125 void getOrientationUsingGetRotationMatrix() {
126 if (mGravityVector == null || mMagneticFieldVector == null) {
127 return;
128 }
129
130 // Get the rotation matrix.
131 // The rotation matrix that transforms from the body frame to the earth
132 // frame.
133 float[] deviceRotationMatrix = new float[9];
134 if (!SensorManager.getRotationMatrix(deviceRotationMatrix, null, mGravit yVector,
135 mMagneticFieldVector)) {
136 return;
137 }
138
139 // Convert rotation matrix to rotation angles.
140 // Assuming that the rotations are appied in the order listed at
141 // http://developer.android.com/reference/android/hardware/SensorEvent.h tml#values
142 // the rotations are applied about the same axes and in the same order a s required by the
143 // API. The only conversions are sign changes as follows. The angles ar e in radians
144
145 float[] rotationAngles = new float[3];
146 SensorManager.getOrientation(deviceRotationMatrix, rotationAngles);
147
148 double alpha = Math.toDegrees(-rotationAngles[0]);
149 while (alpha < 0.0) {
150 alpha += 360.0; // [0, 360)
151 }
152
153 double beta = Math.toDegrees(-rotationAngles[1]);
154 while (beta < -180.0) {
155 beta += 360.0; // [-180, 180)
156 }
157
158 double gamma = Math.toDegrees(rotationAngles[2]);
159 while (gamma < -90.0) {
160 gamma += 360.0; // [-90, 90)
161 }
162
163 gotOrientation(alpha, beta, gamma);
164 }
165
166 boolean registerForSensors(int rateInMilliseconds) {
167 if (registerForSensorType(Sensor.TYPE_ACCELEROMETER, rateInMilliseconds)
168 && registerForSensorType(Sensor.TYPE_MAGNETIC_FIELD, rateInMilli seconds)) {
169 return true;
170 }
171 unregisterForSensors();
172 return false;
173 }
174
175 private SensorManager getSensorManager() {
176 if (mSensorManager != null) {
177 return mSensorManager;
178 }
179 mSensorManager = (SensorManager)WeakContext.getSystemService(Context.SEN SOR_SERVICE);
180 return mSensorManager;
181 }
182
183 void unregisterForSensors() {
184 SensorManager sensorManager = getSensorManager();
185 if (sensorManager == null) {
186 return;
187 }
188 sensorManager.unregisterListener(this);
189 }
190
191 boolean registerForSensorType(int type, int rateInMilliseconds) {
192 SensorManager sensorManager = getSensorManager();
193 if (sensorManager == null) {
194 return false;
195 }
196 List<Sensor> sensors = sensorManager.getSensorList(type);
197 if (sensors.isEmpty()) {
198 return false;
199 }
200
201 final int rateInMicroseconds = 1000 * rateInMilliseconds;
202 // We want to err on the side of getting more events than we need.
203 final int requestedRate = rateInMicroseconds / 2;
204
205 // TODO(steveblock): Consider handling multiple sensors.
206 return sensorManager.registerListener(this, sensors.get(0), requestedRat e, getHandler());
207 }
208
209 void gotOrientation(double alpha, double beta, double gamma) {
210 synchronized (mNativePtrLock) {
211 if (mNativePtr != 0) {
212 nativeGotOrientation(mNativePtr, alpha, beta, gamma);
213 }
214 }
215 }
216
217 private Handler getHandler() {
218 synchronized (mHandlerLock) {
219 // If we don't have a background thread, start it now.
220 if (mThread == null) {
221 mThread = new Thread(new Runnable() {
222 @Override
223 public void run() {
224 Looper.prepare();
225 // Our Handler doesn't actually have to do anything, bec ause
226 // SensorManager posts directly to the underlying Looper .
227 setHandler(new Handler());
228 Looper.loop();
229 }
230 });
231 mThread.start();
232 }
233 // Wait for the background thread to spin up.
234 while (mHandler == null) {
235 try {
236 mHandlerLock.wait();
237 } catch (InterruptedException e) {
238 // Somebody doesn't want us to wait! That's okay, SensorMana ger accepts null.
239 return null;
240 }
241 }
242 return mHandler;
243 }
244 }
245
246 private void setHandler(Handler handler) {
247 synchronized (mHandlerLock) {
248 mHandler = handler;
249 mHandlerLock.notify();
250 }
251 }
252
253 @CalledByNative
254 private static DeviceOrientation getInstance() {
255 synchronized (sSingletonLock) {
256 if (sSingleton == null) {
257 sSingleton = new DeviceOrientation();
258 }
259 return sSingleton;
260 }
261 }
262
263 /**
264 * See chrome/browser/device_orientation/data_fetcher_impl_android.cc
265 */
266 private native void nativeGotOrientation(
267 int nativeDataFetcherImplAndroid,
268 double alpha, double beta, double gamma);
269 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698