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 AccelerometerListener(Context context)91 public AccelerometerListener(Context context) { 92 mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); 93 mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 94 } 95 setListener(OrientationListener listener)96 public void setListener(OrientationListener listener) { 97 mListener = listener; 98 } 99 enable(boolean enable)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 setOrientation(int orientation)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 onSensorEvent(double x, double y, double z)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 orientationChanged(int orientation)171 void orientationChanged(int orientation); 172 } 173 } 174