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