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