Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2009 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 com.android.phone;
     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.util.Log;
     27 
     28 /**
     29  * This class is used to listen to the accelerometer to monitor the
     30  * orientation of the phone. The client of this class is notified when
     31  * the orientation changes between horizontal and vertical.
     32  */
     33 public final class AccelerometerListener {
     34     private static final String TAG = "AccelerometerListener";
     35     private static final boolean DEBUG = true;
     36     private static final boolean VDEBUG = false;
     37 
     38     private SensorManager mSensorManager;
     39     private Sensor mSensor;
     40 
     41     // mOrientation is the orientation value most recently reported to the client.
     42     private int mOrientation;
     43 
     44     // mPendingOrientation is the latest orientation computed based on the sensor value.
     45     // This is sent to the client after a rebounce delay, at which point it is copied to
     46     // mOrientation.
     47     private int mPendingOrientation;
     48 
     49     private OrientationListener mListener;
     50 
     51     // Device orientation
     52     public static final int ORIENTATION_UNKNOWN = 0;
     53     public static final int ORIENTATION_VERTICAL = 1;
     54     public static final int ORIENTATION_HORIZONTAL = 2;
     55 
     56     private static final int ORIENTATION_CHANGED = 1234;
     57 
     58     private static final int VERTICAL_DEBOUNCE = 100;
     59     private static final int HORIZONTAL_DEBOUNCE = 500;
     60     private static final double VERTICAL_ANGLE = 50.0;
     61 
     62     public interface OrientationListener {
     63         public void orientationChanged(int orientation);
     64     }
     65 
     66     public AccelerometerListener(Context context, OrientationListener listener) {
     67         mListener = listener;
     68         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
     69         mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
     70     }
     71 
     72     public void enable(boolean enable) {
     73         if (DEBUG) Log.d(TAG, "enable(" + enable + ")");
     74         synchronized (this) {
     75             if (enable) {
     76                 mOrientation = ORIENTATION_UNKNOWN;
     77                 mPendingOrientation = ORIENTATION_UNKNOWN;
     78                 mSensorManager.registerListener(mSensorListener, mSensor,
     79                         SensorManager.SENSOR_DELAY_NORMAL);
     80             } else {
     81                 mSensorManager.unregisterListener(mSensorListener);
     82                 mHandler.removeMessages(ORIENTATION_CHANGED);
     83             }
     84         }
     85     }
     86 
     87     private void setOrientation(int orientation) {
     88         synchronized (this) {
     89             if (mPendingOrientation == orientation) {
     90                 // Pending orientation has not changed, so do nothing.
     91                 return;
     92             }
     93 
     94             // Cancel any pending messages.
     95             // We will either start a new timer or cancel alltogether
     96             // if the orientation has not changed.
     97             mHandler.removeMessages(ORIENTATION_CHANGED);
     98 
     99             if (mOrientation != orientation) {
    100                 // Set timer to send an event if the orientation has changed since its
    101                 // previously reported value.
    102                 mPendingOrientation = orientation;
    103                 Message m = mHandler.obtainMessage(ORIENTATION_CHANGED);
    104                 // set delay to our debounce timeout
    105                 int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE
    106                                                                  : HORIZONTAL_DEBOUNCE);
    107                 mHandler.sendMessageDelayed(m, delay);
    108             } else {
    109                 // no message is pending
    110                 mPendingOrientation = ORIENTATION_UNKNOWN;
    111             }
    112         }
    113     }
    114 
    115     private void onSensorEvent(double x, double y, double z) {
    116         if (VDEBUG) Log.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")");
    117 
    118         // If some values are exactly zero, then likely the sensor is not powered up yet.
    119         // ignore these events to avoid false horizontal positives.
    120         if (x == 0.0 || y == 0.0 || z == 0.0) return;
    121 
    122         // magnitude of the acceleration vector projected onto XY plane
    123         double xy = Math.sqrt(x*x + y*y);
    124         // compute the vertical angle
    125         double angle = Math.atan2(xy, z);
    126         // convert to degrees
    127         angle = angle * 180.0 / Math.PI;
    128         int orientation = (angle >  VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL);
    129         if (VDEBUG) Log.d(TAG, "angle: " + angle + " orientation: " + orientation);
    130         setOrientation(orientation);
    131     }
    132 
    133     SensorEventListener mSensorListener = new SensorEventListener() {
    134         public void onSensorChanged(SensorEvent event) {
    135             onSensorEvent(event.values[0], event.values[1], event.values[2]);
    136         }
    137 
    138         public void onAccuracyChanged(Sensor sensor, int accuracy) {
    139             // ignore
    140         }
    141     };
    142 
    143     Handler mHandler = new Handler() {
    144         public void handleMessage(Message msg) {
    145             switch (msg.what) {
    146             case ORIENTATION_CHANGED:
    147                 synchronized (this) {
    148                     mOrientation = mPendingOrientation;
    149                     if (DEBUG) {
    150                         Log.d(TAG, "orientation: " +
    151                             (mOrientation == ORIENTATION_HORIZONTAL ? "horizontal"
    152                                 : (mOrientation == ORIENTATION_VERTICAL ? "vertical"
    153                                     : "unknown")));
    154                     }
    155                     mListener.orientationChanged(mOrientation);
    156                 }
    157                 break;
    158             }
    159         }
    160     };
    161 }
    162