• 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 com.android.dialer.common.LogUtil;
27 
28 /**
29  * This class is used to listen to the accelerometer to monitor the orientation of the phone. The
30  * client of this class is notified when the orientation changes between horizontal and vertical.
31  */
32 public class AccelerometerListener {
33 
34   // Device orientation
35   public static final int ORIENTATION_UNKNOWN = 0;
36   public static final int ORIENTATION_VERTICAL = 1;
37   public static final int ORIENTATION_HORIZONTAL = 2;
38   private static final String TAG = "AccelerometerListener";
39   private static final boolean DEBUG = true;
40   private static final boolean VDEBUG = false;
41   private static final int ORIENTATION_CHANGED = 1234;
42   private static final int VERTICAL_DEBOUNCE = 100;
43   private static final int HORIZONTAL_DEBOUNCE = 500;
44   private static final double VERTICAL_ANGLE = 50.0;
45   private SensorManager sensorManager;
46   private Sensor sensor;
47   // mOrientation is the orientation value most recently reported to the client.
48   private int orientation;
49   // mPendingOrientation is the latest orientation computed based on the sensor value.
50   // This is sent to the client after a rebounce delay, at which point it is copied to
51   // mOrientation.
52   private int pendingOrientation;
53   private OrientationListener listener;
54   Handler handler =
55       new Handler() {
56         @Override
57         public void handleMessage(Message msg) {
58           switch (msg.what) {
59             case ORIENTATION_CHANGED:
60               synchronized (this) {
61                 orientation = pendingOrientation;
62                 if (DEBUG) {
63                   LogUtil.d(
64                       TAG,
65                       "orientation: "
66                           + (orientation == ORIENTATION_HORIZONTAL
67                               ? "horizontal"
68                               : (orientation == ORIENTATION_VERTICAL ? "vertical" : "unknown")));
69                 }
70                 if (listener != null) {
71                   listener.orientationChanged(orientation);
72                 }
73               }
74               break;
75           }
76         }
77       };
78   SensorEventListener sensorListener =
79       new SensorEventListener() {
80         @Override
81         public void onSensorChanged(SensorEvent event) {
82           onSensorEvent(event.values[0], event.values[1], event.values[2]);
83         }
84 
85         @Override
86         public void onAccuracyChanged(Sensor sensor, int accuracy) {
87           // ignore
88         }
89       };
90 
AccelerometerListener(Context context)91   public AccelerometerListener(Context context) {
92     sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
93     sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
94   }
95 
setListener(OrientationListener listener)96   public void setListener(OrientationListener listener) {
97     this.listener = listener;
98   }
99 
enable(boolean enable)100   public void enable(boolean enable) {
101     if (DEBUG) {
102       LogUtil.d(TAG, "enable(" + enable + ")");
103     }
104     synchronized (this) {
105       if (enable) {
106         orientation = ORIENTATION_UNKNOWN;
107         pendingOrientation = ORIENTATION_UNKNOWN;
108         sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
109       } else {
110         sensorManager.unregisterListener(sensorListener);
111         handler.removeMessages(ORIENTATION_CHANGED);
112       }
113     }
114   }
115 
setOrientation(int orientation)116   private void setOrientation(int orientation) {
117     synchronized (this) {
118       if (pendingOrientation == orientation) {
119         // Pending orientation has not changed, so do nothing.
120         return;
121       }
122 
123       // Cancel any pending messages.
124       // We will either start a new timer or cancel alltogether
125       // if the orientation has not changed.
126       handler.removeMessages(ORIENTATION_CHANGED);
127 
128       if (this.orientation != orientation) {
129         // Set timer to send an event if the orientation has changed since its
130         // previously reported value.
131         pendingOrientation = orientation;
132         final Message m = handler.obtainMessage(ORIENTATION_CHANGED);
133         // set delay to our debounce timeout
134         int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE : HORIZONTAL_DEBOUNCE);
135         handler.sendMessageDelayed(m, delay);
136       } else {
137         // no message is pending
138         pendingOrientation = ORIENTATION_UNKNOWN;
139       }
140     }
141   }
142 
onSensorEvent(double x, double y, double z)143   private void onSensorEvent(double x, double y, double z) {
144     if (VDEBUG) {
145       LogUtil.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")");
146     }
147 
148     // If some values are exactly zero, then likely the sensor is not powered up yet.
149     // ignore these events to avoid false horizontal positives.
150     if (x == 0.0 || y == 0.0 || z == 0.0) {
151       return;
152     }
153 
154     // magnitude of the acceleration vector projected onto XY plane
155     final double xy = Math.hypot(x, y);
156     // compute the vertical angle
157     double angle = Math.atan2(xy, z);
158     // convert to degrees
159     angle = angle * 180.0 / Math.PI;
160     final int orientation =
161         (angle > VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL);
162     if (VDEBUG) {
163       LogUtil.d(TAG, "angle: " + angle + " orientation: " + orientation);
164     }
165     setOrientation(orientation);
166   }
167 
168   public interface OrientationListener {
169 
orientationChanged(int orientation)170     void orientationChanged(int orientation);
171   }
172 }
173