103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood/* 203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * Copyright (C) 2009 The Android Open Source Project 303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * 403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * you may not use this file except in compliance with the License. 603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * You may obtain a copy of the License at 703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * 803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * 1003adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * Unless required by applicable law or agreed to in writing, software 1103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 1203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * See the License for the specific language governing permissions and 1403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * limitations under the License. 1503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood */ 1603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 1703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwoodpackage com.android.phone; 1803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 1903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwoodimport android.content.Context; 2003adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwoodimport android.hardware.Sensor; 2103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwoodimport android.hardware.SensorEvent; 2203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwoodimport android.hardware.SensorEventListener; 2303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwoodimport android.hardware.SensorManager; 2403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwoodimport android.os.Handler; 2503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwoodimport android.os.Message; 26f0bfbeb7124696e67b77a4a9e19f7ecc41c95850Mike Lockwoodimport android.util.Log; 2703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 2803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood/** 2903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * This class is used to listen to the accelerometer to monitor the 3003adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * orientation of the phone. The client of this class is notified when 3103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood * the orientation changes between horizontal and vertical. 3203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood */ 3303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwoodpublic final class AccelerometerListener { 34f0bfbeb7124696e67b77a4a9e19f7ecc41c95850Mike Lockwood private static final String TAG = "AccelerometerListener"; 354a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood private static final boolean DEBUG = true; 364a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood private static final boolean VDEBUG = false; 37f0bfbeb7124696e67b77a4a9e19f7ecc41c95850Mike Lockwood 3803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private SensorManager mSensorManager; 3903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private Sensor mSensor; 40304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood 41304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // mOrientation is the orientation value most recently reported to the client. 4203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private int mOrientation; 43304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood 44304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // mPendingOrientation is the latest orientation computed based on the sensor value. 45304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // This is sent to the client after a rebounce delay, at which point it is copied to 46304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // mOrientation. 4703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private int mPendingOrientation; 48304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood 4903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private OrientationListener mListener; 5003adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 5103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood // Device orientation 5203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public static final int ORIENTATION_UNKNOWN = 0; 5303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public static final int ORIENTATION_VERTICAL = 1; 5403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public static final int ORIENTATION_HORIZONTAL = 2; 5503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 5603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private static final int ORIENTATION_CHANGED = 1234; 5703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 5803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private static final int VERTICAL_DEBOUNCE = 100; 5903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private static final int HORIZONTAL_DEBOUNCE = 500; 60f0bfbeb7124696e67b77a4a9e19f7ecc41c95850Mike Lockwood private static final double VERTICAL_ANGLE = 50.0; 6103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 6203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public interface OrientationListener { 6303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public void orientationChanged(int orientation); 6403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 6503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 6603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public AccelerometerListener(Context context, OrientationListener listener) { 6703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mListener = listener; 6803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); 6903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 7003adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 7103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 7203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public void enable(boolean enable) { 734a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood if (DEBUG) Log.d(TAG, "enable(" + enable + ")"); 7403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood synchronized (this) { 7503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood if (enable) { 7603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mOrientation = ORIENTATION_UNKNOWN; 7703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mPendingOrientation = ORIENTATION_UNKNOWN; 7803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mSensorManager.registerListener(mSensorListener, mSensor, 7903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood SensorManager.SENSOR_DELAY_NORMAL); 8003adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } else { 8103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mSensorManager.unregisterListener(mSensorListener); 8203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mHandler.removeMessages(ORIENTATION_CHANGED); 8303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 8403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 8503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 8603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 8703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private void setOrientation(int orientation) { 8803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood synchronized (this) { 89304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood if (mPendingOrientation == orientation) { 90304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // Pending orientation has not changed, so do nothing. 91304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood return; 92304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood } 93304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood 94304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // Cancel any pending messages. 95304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // We will either start a new timer or cancel alltogether 96304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // if the orientation has not changed. 97304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood mHandler.removeMessages(ORIENTATION_CHANGED); 98304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood 99304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood if (mOrientation != orientation) { 100304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // Set timer to send an event if the orientation has changed since its 101304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // previously reported value. 10203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mPendingOrientation = orientation; 10303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood Message m = mHandler.obtainMessage(ORIENTATION_CHANGED); 10403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood // set delay to our debounce timeout 10503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE 10603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood : HORIZONTAL_DEBOUNCE); 10703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mHandler.sendMessageDelayed(m, delay); 108304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood } else { 109304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood // no message is pending 110304041d6240536bbe2171e39b5da8423a222cc1bMike Lockwood mPendingOrientation = ORIENTATION_UNKNOWN; 11103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 11203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 11303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 11403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 11503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood private void onSensorEvent(double x, double y, double z) { 1164a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood if (VDEBUG) Log.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")"); 117f0bfbeb7124696e67b77a4a9e19f7ecc41c95850Mike Lockwood 118f0bfbeb7124696e67b77a4a9e19f7ecc41c95850Mike Lockwood // If some values are exactly zero, then likely the sensor is not powered up yet. 119f0bfbeb7124696e67b77a4a9e19f7ecc41c95850Mike Lockwood // ignore these events to avoid false horizontal positives. 120f0bfbeb7124696e67b77a4a9e19f7ecc41c95850Mike Lockwood if (x == 0.0 || y == 0.0 || z == 0.0) return; 121f0bfbeb7124696e67b77a4a9e19f7ecc41c95850Mike Lockwood 12203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood // magnitude of the acceleration vector projected onto XY plane 12303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood double xy = Math.sqrt(x*x + y*y); 12403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood // compute the vertical angle 12503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood double angle = Math.atan2(xy, z); 12603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood // convert to degrees 12703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood angle = angle * 180.0 / Math.PI; 12803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood int orientation = (angle > VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL); 1294a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood if (VDEBUG) Log.d(TAG, "angle: " + angle + " orientation: " + orientation); 13003adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood setOrientation(orientation); 13103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 13203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 13303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood SensorEventListener mSensorListener = new SensorEventListener() { 13403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public void onSensorChanged(SensorEvent event) { 13503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood onSensorEvent(event.values[0], event.values[1], event.values[2]); 13603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 13703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 13803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public void onAccuracyChanged(Sensor sensor, int accuracy) { 13903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood // ignore 14003adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 14103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood }; 14203adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood 14303adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood Handler mHandler = new Handler() { 14403adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood public void handleMessage(Message msg) { 14503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood switch (msg.what) { 14603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood case ORIENTATION_CHANGED: 14703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood synchronized (this) { 14803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mOrientation = mPendingOrientation; 1494a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood if (DEBUG) { 1504a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood Log.d(TAG, "orientation: " + 1514a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood (mOrientation == ORIENTATION_HORIZONTAL ? "horizontal" 1524a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood : (mOrientation == ORIENTATION_VERTICAL ? "vertical" 1534a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood : "unknown"))); 1544a0fb8b7468829b1035ee9801c2c5a587d9bf18aMike Lockwood } 15503adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood mListener.orientationChanged(mOrientation); 15603adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 15703adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood break; 15803adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 15903adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood } 16003adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood }; 16103adaac30038029e90dbbb266bacb3f2abb32397Mike Lockwood} 162