• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.app.WindowConfiguration.ROTATION_UNDEFINED;
20 
21 import android.annotation.NonNull;
22 import android.content.Context;
23 import android.content.res.CompatibilityInfo;
24 import android.hardware.Sensor;
25 import android.hardware.SensorEvent;
26 import android.hardware.SensorEventListener;
27 import android.hardware.SensorManager;
28 import android.util.Log;
29 import android.window.DesktopModeFlags;
30 
31 /**
32  * Helper class for receiving notifications from the SensorManager when
33  * the orientation of the device has changed.
34  */
35 public abstract class OrientationEventListener {
36     private static final String TAG = "OrientationEventListener";
37     private static final boolean DEBUG = false;
38     private static final boolean localLOGV = false;
39     private int mOrientation = ORIENTATION_UNKNOWN;
40     private SensorManager mSensorManager;
41     private boolean mEnabled = false;
42     private int mRate;
43     private Sensor mSensor;
44     private SensorEventListener mSensorEventListener;
45     private OrientationListener mOldListener;
46 
47     /**
48      * Returned from onOrientationChanged when the device orientation cannot be determined
49      * (typically when the device is in a close to flat position).
50      *
51      *  @see #onOrientationChanged
52      */
53     public static final int ORIENTATION_UNKNOWN = -1;
54 
55     /**
56      * Creates a new OrientationEventListener.
57      *
58      * @param context for the OrientationEventListener.
59      */
OrientationEventListener(Context context)60     public OrientationEventListener(Context context) {
61         this(context, SensorManager.SENSOR_DELAY_NORMAL);
62     }
63 
64     /**
65      * Creates a new OrientationEventListener.
66      *
67      * @param context for the OrientationEventListener.
68      * @param rate at which sensor events are processed (see also
69      * {@link android.hardware.SensorManager SensorManager}). Use the default
70      * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL
71      * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
72      */
OrientationEventListener(Context context, int rate)73     public OrientationEventListener(Context context, int rate) {
74         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
75         mRate = rate;
76         mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
77         if (mSensor != null) {
78             // Create listener only if sensors do exist.
79             mSensorEventListener =
80                     DesktopModeFlags.ENABLE_CAMERA_COMPAT_SIMULATE_REQUESTED_ORIENTATION.isTrue()
81                             ? new CompatSensorEventListenerImpl(new SensorEventListenerImpl())
82                             : new SensorEventListenerImpl();
83         }
84     }
85 
registerListener(OrientationListener lis)86     void registerListener(OrientationListener lis) {
87         mOldListener = lis;
88     }
89 
90     /**
91      * Enables the OrientationEventListener so it will monitor the sensor and call
92      * {@link #onOrientationChanged} when the device orientation changes.
93      */
enable()94     public void enable() {
95         if (mSensor == null) {
96             Log.w(TAG, "Cannot detect sensors. Not enabled");
97             return;
98         }
99         if (mEnabled == false) {
100             if (localLOGV) Log.d(TAG, "OrientationEventListener enabled");
101             mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
102             mEnabled = true;
103         }
104     }
105 
106     /**
107      * Disables the OrientationEventListener.
108      */
disable()109     public void disable() {
110         if (mSensor == null) {
111             Log.w(TAG, "Cannot detect sensors. Invalid disable");
112             return;
113         }
114         if (mEnabled == true) {
115             if (localLOGV) Log.d(TAG, "OrientationEventListener disabled");
116             mSensorManager.unregisterListener(mSensorEventListener);
117             mEnabled = false;
118         }
119     }
120 
121     class SensorEventListenerImpl implements SensorEventListener {
122         private static final int _DATA_X = 0;
123         private static final int _DATA_Y = 1;
124         private static final int _DATA_Z = 2;
125 
onSensorChanged(SensorEvent event)126         public void onSensorChanged(SensorEvent event) {
127             float[] values = event.values;
128             int orientation = ORIENTATION_UNKNOWN;
129             float X = -values[_DATA_X];
130             float Y = -values[_DATA_Y];
131             float Z = -values[_DATA_Z];
132             float magnitude = X*X + Y*Y;
133             // Don't trust the angle if the magnitude is small compared to the y value
134             if (magnitude * 4 >= Z*Z) {
135                 float OneEightyOverPi = 57.29577957855f;
136                 float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi;
137                 orientation = 90 - (int)Math.round(angle);
138                 // normalize to 0 - 359 range
139                 while (orientation >= 360) {
140                     orientation -= 360;
141                 }
142                 while (orientation < 0) {
143                     orientation += 360;
144                 }
145             }
146             if (mOldListener != null) {
147                 mOldListener.onSensorChanged(Sensor.TYPE_ACCELEROMETER, event.values);
148             }
149             if (orientation != mOrientation) {
150                 mOrientation = orientation;
151                 onOrientationChanged(orientation);
152             }
153         }
154 
onAccuracyChanged(Sensor sensor, int accuracy)155         public void onAccuracyChanged(Sensor sensor, int accuracy) {
156 
157         }
158     }
159 
160     /** Decorator to the {@link SensorEventListenerImpl}, which provides compat values if needed. */
161     class CompatSensorEventListenerImpl implements SensorEventListener {
162         // SensorEventListener without compatibility capabilities.
163         final SensorEventListenerImpl mSensorEventListener;
164 
CompatSensorEventListenerImpl(@onNull SensorEventListenerImpl sensorEventListener)165         CompatSensorEventListenerImpl(@NonNull SensorEventListenerImpl sensorEventListener) {
166             mSensorEventListener = sensorEventListener;
167         }
168 
onSensorChanged(SensorEvent event)169         public void onSensorChanged(SensorEvent event) {
170             // If the display rotation override is set, the same override should be applied to
171             // this orientation too. This rotation override will only be set when an app has a
172             // camera open and it is in camera compat mode for desktop windowing (freeform mode).
173             // Values of this override is Surface.ROTATION_0/90/180/270, or
174             // WindowConfiguration.ROTATION_UNDEFINED when not set.
175             if (CompatibilityInfo.getOverrideDisplayRotation() != ROTATION_UNDEFINED) {
176                 // SensorEventListener reports the rotation in the opposite direction from the
177                 // display rotation.
178                 int orientation = (360 - CompatibilityInfo.getOverrideDisplayRotation() * 90) % 360;
179                 if (orientation != mOrientation) {
180                     mOrientation = orientation;
181                     onOrientationChanged(orientation);
182                 }
183                 // `mOldListener` is deprecated and returns 3D values, which are highly unlikely to
184                 // be used for orienting camera image. Thus this listener is not called here, as
185                 // opposed to extrapolating values from display rotation, from 1D->3D.
186             } else {
187                 // Use the default implementation: calculate the orientation from event coordinates.
188                 // This method will call OrientationEventListener.onOrientationChanged(orientation)
189                 // if the orientation has changed.
190                 mSensorEventListener.onSensorChanged(event);
191             }
192         }
193 
onAccuracyChanged(Sensor sensor, int accuracy)194         public void onAccuracyChanged(Sensor sensor, int accuracy) {
195 
196         }
197     }
198 
199     /*
200      * Returns true if sensor is enabled and false otherwise
201      */
canDetectOrientation()202     public boolean canDetectOrientation() {
203         return mSensor != null;
204     }
205 
206     /**
207      * Called when the orientation of the device has changed.
208      * orientation parameter is in degrees, ranging from 0 to 359.
209      * orientation is 0 degrees when the device is oriented in its natural position,
210      * 90 degrees when its left side is at the top, 180 degrees when it is upside down,
211      * and 270 degrees when its right side is to the top.
212      * {@link #ORIENTATION_UNKNOWN} is returned when the device is close to flat
213      * and the orientation cannot be determined.
214      *
215      * @param orientation The new orientation of the device.
216      *
217      *  @see #ORIENTATION_UNKNOWN
218      */
onOrientationChanged(int orientation)219     abstract public void onOrientationChanged(int orientation);
220 }
221