• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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