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