1dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block/*
2dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block * Copyright (C) 2010 The Android Open Source Project
3dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block *
4dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block * Licensed under the Apache License, Version 2.0 (the "License");
5dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block * you may not use this file except in compliance with the License.
6dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block * You may obtain a copy of the License at
7dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block *
8dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block *      http://www.apache.org/licenses/LICENSE-2.0
9dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block *
10dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block * Unless required by applicable law or agreed to in writing, software
11dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block * distributed under the License is distributed on an "AS IS" BASIS,
12dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block * See the License for the specific language governing permissions and
14dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block * limitations under the License.
15dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block */
16dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
17dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockpackage android.webkit;
18dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
19dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockimport android.content.Context;
20dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockimport android.hardware.Sensor;
21dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockimport android.hardware.SensorEvent;
22dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockimport android.hardware.SensorEventListener;
23dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockimport android.hardware.SensorManager;
24dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockimport android.os.Handler;
25dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockimport android.os.Message;
261be73390778eb1b033a4db6339c8a8b325dfaad9Steve Blockimport android.webkit.DeviceMotionAndOrientationManager;
27dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockimport java.lang.Runnable;
28dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockimport java.util.List;
29dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
30dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
31dc82a29b1108622694fb9f1036e2225eafac58c1Steve Blockfinal class DeviceMotionService implements SensorEventListener {
321be73390778eb1b033a4db6339c8a8b325dfaad9Steve Block    private DeviceMotionAndOrientationManager mManager;
33dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private boolean mIsRunning;
34dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private Handler mHandler;
35dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private SensorManager mSensorManager;
36dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private Context mContext;
37dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private boolean mHaveSentErrorEvent;
38dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private Runnable mUpdateRunnable;
39dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private float mLastAcceleration[];
40dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
41dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private static final int INTERVAL_MILLIS = 100;
42dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
431be73390778eb1b033a4db6339c8a8b325dfaad9Steve Block    public DeviceMotionService(DeviceMotionAndOrientationManager manager, Context context) {
44dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mManager = manager;
45dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        assert(mManager != null);
46dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mContext = context;
47dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        assert(mContext != null);
48dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block     }
49dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
50dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    public void start() {
51dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mIsRunning = true;
52dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        registerForSensor();
53dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
54dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
55dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    public void stop() {
56dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mIsRunning = false;
57dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        stopSendingUpdates();
58dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        unregisterFromSensor();
59dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
60dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
61dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    public void suspend() {
62dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        if (mIsRunning) {
63dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            stopSendingUpdates();
64dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            unregisterFromSensor();
65dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        }
66dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
67dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
68dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    public void resume() {
69dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        if (mIsRunning) {
70dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            registerForSensor();
71dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        }
72dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
73dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
74dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private void sendErrorEvent() {
75dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
76dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        // The spec requires that each listener receives the error event only once.
77dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        if (mHaveSentErrorEvent)
78dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            return;
79dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mHaveSentErrorEvent = true;
80dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        createHandler();
81dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mHandler.post(new Runnable() {
82dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            @Override
83dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            public void run() {
84dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
85dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                if (mIsRunning) {
86dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                    // The special case of all nulls is used to signify a failure to get data.
87dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                    mManager.onMotionChange(null, null, null, 0.0);
88dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                }
89dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            }
90dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        });
91dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
92dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
93dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private void createHandler() {
94dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        if (mHandler != null) {
95dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            return;
96dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        }
97dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
98dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mHandler = new Handler();
99dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mUpdateRunnable = new Runnable() {
100dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            @Override
101dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            public void run() {
102d09001fea476ca6c6eaff5e29a1bb6f3aebe5bd5Steve Block                assert mIsRunning;
103dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                mManager.onMotionChange(new Double(mLastAcceleration[0]),
104dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                        new Double(mLastAcceleration[1]), new Double(mLastAcceleration[2]),
105dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                        INTERVAL_MILLIS);
106dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                mHandler.postDelayed(mUpdateRunnable, INTERVAL_MILLIS);
107dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                // Now that we have successfully sent some data, reset whether we've sent an error.
108dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                mHaveSentErrorEvent = false;
109dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            }
110dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        };
111dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
112dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
113dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private void startSendingUpdates() {
114dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        createHandler();
115dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mUpdateRunnable.run();
116dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
117dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
118dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private void stopSendingUpdates() {
119dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mHandler.removeCallbacks(mUpdateRunnable);
120dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mLastAcceleration = null;
121dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
122dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
123dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private void registerForSensor() {
124dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        if (!registerForAccelerometerSensor()) {
125dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            sendErrorEvent();
126dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        }
127dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
128dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
129dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private SensorManager getSensorManager() {
130dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
131dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        if (mSensorManager == null) {
132dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
133dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        }
134dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        return mSensorManager;
135dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
136dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
137dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private boolean registerForAccelerometerSensor() {
138dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        List<Sensor> sensors = getSensorManager().getSensorList(Sensor.TYPE_ACCELEROMETER);
139dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        if (sensors.isEmpty()) {
140dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            return false;
141dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        }
142dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        createHandler();
143dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        // TODO: Consider handling multiple sensors.
144dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        return getSensorManager().registerListener(
145dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block                this, sensors.get(0), SensorManager.SENSOR_DELAY_UI, mHandler);
146dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
147dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
148dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    private void unregisterFromSensor() {
149dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        getSensorManager().unregisterListener(this);
150dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
151dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
152dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    /**
153dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block     * SensorEventListener implementation.
154dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block     * Callbacks happen on the thread on which we registered - the WebCore thread.
155dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block     */
1565ba2efeb9faaf7db9da205102b9a7f40b4b89f27Steve Block    @Override
157dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    public void onSensorChanged(SensorEvent event) {
158dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        assert(event.values.length == 3);
159dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
160dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        assert(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER);
161dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
162d09001fea476ca6c6eaff5e29a1bb6f3aebe5bd5Steve Block        // We may get callbacks after the call to getSensorManager().unregisterListener() returns.
163d09001fea476ca6c6eaff5e29a1bb6f3aebe5bd5Steve Block        if (!mIsRunning) {
164d09001fea476ca6c6eaff5e29a1bb6f3aebe5bd5Steve Block            return;
165d09001fea476ca6c6eaff5e29a1bb6f3aebe5bd5Steve Block        }
166d09001fea476ca6c6eaff5e29a1bb6f3aebe5bd5Steve Block
167dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        boolean firstData = mLastAcceleration == null;
168dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        mLastAcceleration = event.values;
169dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        if (firstData) {
170dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block            startSendingUpdates();
171dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        }
172dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
173dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block
1745ba2efeb9faaf7db9da205102b9a7f40b4b89f27Steve Block    @Override
175dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    public void onAccuracyChanged(Sensor sensor, int accuracy) {
176dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block        assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
177dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block    }
178dc82a29b1108622694fb9f1036e2225eafac58c1Steve Block}
179