/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.phone; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Handler; import android.os.Message; import android.util.Log; /** * This class is used to listen to the accelerometer to monitor the * orientation of the phone. The client of this class is notified when * the orientation changes between horizontal and vertical. */ public final class AccelerometerListener { private static final String TAG = "AccelerometerListener"; private static final boolean DEBUG = true; private static final boolean VDEBUG = false; private SensorManager mSensorManager; private Sensor mSensor; // mOrientation is the orientation value most recently reported to the client. private int mOrientation; // mPendingOrientation is the latest orientation computed based on the sensor value. // This is sent to the client after a rebounce delay, at which point it is copied to // mOrientation. private int mPendingOrientation; private OrientationListener mListener; // Device orientation public static final int ORIENTATION_UNKNOWN = 0; public static final int ORIENTATION_VERTICAL = 1; public static final int ORIENTATION_HORIZONTAL = 2; private static final int ORIENTATION_CHANGED = 1234; private static final int VERTICAL_DEBOUNCE = 100; private static final int HORIZONTAL_DEBOUNCE = 500; private static final double VERTICAL_ANGLE = 50.0; public interface OrientationListener { public void orientationChanged(int orientation); } public AccelerometerListener(Context context, OrientationListener listener) { mListener = listener; mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); } public void enable(boolean enable) { if (DEBUG) Log.d(TAG, "enable(" + enable + ")"); synchronized (this) { if (enable) { mOrientation = ORIENTATION_UNKNOWN; mPendingOrientation = ORIENTATION_UNKNOWN; mSensorManager.registerListener(mSensorListener, mSensor, SensorManager.SENSOR_DELAY_NORMAL); } else { mSensorManager.unregisterListener(mSensorListener); mHandler.removeMessages(ORIENTATION_CHANGED); } } } private void setOrientation(int orientation) { synchronized (this) { if (mPendingOrientation == orientation) { // Pending orientation has not changed, so do nothing. return; } // Cancel any pending messages. // We will either start a new timer or cancel alltogether // if the orientation has not changed. mHandler.removeMessages(ORIENTATION_CHANGED); if (mOrientation != orientation) { // Set timer to send an event if the orientation has changed since its // previously reported value. mPendingOrientation = orientation; Message m = mHandler.obtainMessage(ORIENTATION_CHANGED); // set delay to our debounce timeout int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE : HORIZONTAL_DEBOUNCE); mHandler.sendMessageDelayed(m, delay); } else { // no message is pending mPendingOrientation = ORIENTATION_UNKNOWN; } } } private void onSensorEvent(double x, double y, double z) { if (VDEBUG) Log.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")"); // If some values are exactly zero, then likely the sensor is not powered up yet. // ignore these events to avoid false horizontal positives. if (x == 0.0 || y == 0.0 || z == 0.0) return; // magnitude of the acceleration vector projected onto XY plane double xy = Math.sqrt(x*x + y*y); // compute the vertical angle double angle = Math.atan2(xy, z); // convert to degrees angle = angle * 180.0 / Math.PI; int orientation = (angle > VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL); if (VDEBUG) Log.d(TAG, "angle: " + angle + " orientation: " + orientation); setOrientation(orientation); } SensorEventListener mSensorListener = new SensorEventListener() { public void onSensorChanged(SensorEvent event) { onSensorEvent(event.values[0], event.values[1], event.values[2]); } public void onAccuracyChanged(Sensor sensor, int accuracy) { // ignore } }; Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case ORIENTATION_CHANGED: synchronized (this) { mOrientation = mPendingOrientation; if (DEBUG) { Log.d(TAG, "orientation: " + (mOrientation == ORIENTATION_HORIZONTAL ? "horizontal" : (mOrientation == ORIENTATION_VERTICAL ? "vertical" : "unknown"))); } mListener.orientationChanged(mOrientation); } break; } } }; }