1 /*
2  * Copyright (C) 2008 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 android.view;
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.util.Log;
25 
26 /**
27  * Helper class for receiving notifications from the SensorManager when
28  * the orientation of the device has changed.
29  */
30 public abstract class OrientationEventListener {
31     private static final String TAG = "OrientationEventListener";
32     private static final boolean DEBUG = false;
33     private static final boolean localLOGV = false;
34     private int mOrientation = ORIENTATION_UNKNOWN;
35     private SensorManager mSensorManager;
36     private boolean mEnabled = false;
37     private int mRate;
38     private Sensor mSensor;
39     private SensorEventListener mSensorEventListener;
40     private OrientationListener mOldListener;
41 
42     /**
43      * Returned from onOrientationChanged when the device orientation cannot be determined
44      * (typically when the device is in a close to flat position).
45      *
46      *  @see #onOrientationChanged
47      */
48     public static final int ORIENTATION_UNKNOWN = -1;
49 
50     /**
51      * Creates a new OrientationEventListener.
52      *
53      * @param context for the OrientationEventListener.
54      */
OrientationEventListener(Context context)55     public OrientationEventListener(Context context) {
56         this(context, SensorManager.SENSOR_DELAY_NORMAL);
57     }
58 
59     /**
60      * Creates a new OrientationEventListener.
61      *
62      * @param context for the OrientationEventListener.
63      * @param rate at which sensor events are processed (see also
64      * {@link android.hardware.SensorManager SensorManager}). Use the default
65      * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL
66      * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
67      */
OrientationEventListener(Context context, int rate)68     public OrientationEventListener(Context context, int rate) {
69         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
70         mRate = rate;
71         mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
72         if (mSensor != null) {
73             // Create listener only if sensors do exist
74             mSensorEventListener = new SensorEventListenerImpl();
75         }
76     }
77 
registerListener(OrientationListener lis)78     void registerListener(OrientationListener lis) {
79         mOldListener = lis;
80     }
81 
82     /**
83      * Enables the OrientationEventListener so it will monitor the sensor and call
84      * {@link #onOrientationChanged} when the device orientation changes.
85      */
enable()86     public void enable() {
87         if (mSensor == null) {
88             Log.w(TAG, "Cannot detect sensors. Not enabled");
89             return;
90         }
91         if (mEnabled == false) {
92             if (localLOGV) Log.d(TAG, "OrientationEventListener enabled");
93             mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
94             mEnabled = true;
95         }
96     }
97 
98     /**
99      * Disables the OrientationEventListener.
100      */
disable()101     public void disable() {
102         if (mSensor == null) {
103             Log.w(TAG, "Cannot detect sensors. Invalid disable");
104             return;
105         }
106         if (mEnabled == true) {
107             if (localLOGV) Log.d(TAG, "OrientationEventListener disabled");
108             mSensorManager.unregisterListener(mSensorEventListener);
109             mEnabled = false;
110         }
111     }
112 
113     class SensorEventListenerImpl implements SensorEventListener {
114         private static final int _DATA_X = 0;
115         private static final int _DATA_Y = 1;
116         private static final int _DATA_Z = 2;
117 
onSensorChanged(SensorEvent event)118         public void onSensorChanged(SensorEvent event) {
119             float[] values = event.values;
120             int orientation = ORIENTATION_UNKNOWN;
121             float X = -values[_DATA_X];
122             float Y = -values[_DATA_Y];
123             float Z = -values[_DATA_Z];
124             float magnitude = X*X + Y*Y;
125             // Don't trust the angle if the magnitude is small compared to the y value
126             if (magnitude * 4 >= Z*Z) {
127                 float OneEightyOverPi = 57.29577957855f;
128                 float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi;
129                 orientation = 90 - (int)Math.round(angle);
130                 // normalize to 0 - 359 range
131                 while (orientation >= 360) {
132                     orientation -= 360;
133                 }
134                 while (orientation < 0) {
135                     orientation += 360;
136                 }
137             }
138             if (mOldListener != null) {
139                 mOldListener.onSensorChanged(Sensor.TYPE_ACCELEROMETER, event.values);
140             }
141             if (orientation != mOrientation) {
142                 mOrientation = orientation;
143                 onOrientationChanged(orientation);
144             }
145         }
146 
onAccuracyChanged(Sensor sensor, int accuracy)147         public void onAccuracyChanged(Sensor sensor, int accuracy) {
148 
149         }
150     }
151 
152     /*
153      * Returns true if sensor is enabled and false otherwise
154      */
canDetectOrientation()155     public boolean canDetectOrientation() {
156         return mSensor != null;
157     }
158 
159     /**
160      * Called when the orientation of the device has changed.
161      * orientation parameter is in degrees, ranging from 0 to 359.
162      * orientation is 0 degrees when the device is oriented in its natural position,
163      * 90 degrees when its left side is at the top, 180 degrees when it is upside down,
164      * and 270 degrees when its right side is to the top.
165      * {@link #ORIENTATION_UNKNOWN} is returned when the device is close to flat
166      * and the orientation cannot be determined.
167      *
168      * @param orientation The new orientation of the device.
169      *
170      *  @see #ORIENTATION_UNKNOWN
171      */
onOrientationChanged(int orientation)172     abstract public void onOrientationChanged(int orientation);
173 }
174