Home | History | Annotate | Download | only in webkit
      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     @Override
    157     public void onSensorChanged(SensorEvent event) {
    158         assert(event.values.length == 3);
    159         assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
    160         assert(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER);
    161 
    162         // We may get callbacks after the call to getSensorManager().unregisterListener() returns.
    163         if (!mIsRunning) {
    164             return;
    165         }
    166 
    167         boolean firstData = mLastAcceleration == null;
    168         mLastAcceleration = event.values;
    169         if (firstData) {
    170             startSendingUpdates();
    171         }
    172     }
    173 
    174     @Override
    175     public void onAccuracyChanged(Sensor sensor, int accuracy) {
    176         assert WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName());
    177     }
    178 }
    179