1 /*
2  * Copyright (C) 2015 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.content.res.Configuration;
21 import android.view.OrientationEventListener;
22 import android.hardware.SensorManager;
23 import android.view.Surface;
24 import android.content.pm.ActivityInfo;
25 
26 /**
27  * This class listens to Orientation events and overrides onOrientationChanged which gets
28  * invoked when an orientation change occurs. When that happens, we notify InCallUI registrants
29  * of the change.
30  */
31 public class InCallOrientationEventListener extends OrientationEventListener {
32 
33     /**
34      * Screen orientation angles one of 0, 90, 180, 270, 360 in degrees.
35      */
36     public static int SCREEN_ORIENTATION_0 = 0;
37     public static int SCREEN_ORIENTATION_90 = 90;
38     public static int SCREEN_ORIENTATION_180 = 180;
39     public static int SCREEN_ORIENTATION_270 = 270;
40     public static int SCREEN_ORIENTATION_360 = 360;
41 
42     public static int FULL_SENSOR_SCREEN_ORIENTATION =
43             ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
44 
45     public static int NO_SENSOR_SCREEN_ORIENTATION =
46             ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
47 
48     /**
49      * This is to identify dead zones where we won't notify others of orientation changed.
50      * Say for e.g our threshold is x degrees. We will only notify UI when our current rotation is
51      * within x degrees right or left of the screen orientation angles. If it's not within those
52      * ranges, we return SCREEN_ORIENTATION_UNKNOWN and ignore it.
53      */
54     private static int SCREEN_ORIENTATION_UNKNOWN = -1;
55 
56     // Rotation threshold is 10 degrees. So if the rotation angle is within 10 degrees of any of
57     // the above angles, we will notify orientation changed.
58     private static int ROTATION_THRESHOLD = 10;
59 
60 
61     /**
62      * Cache the current rotation of the device.
63      */
64     private static int sCurrentOrientation = SCREEN_ORIENTATION_0;
65 
InCallOrientationEventListener(Context context)66     public InCallOrientationEventListener(Context context) {
67         super(context);
68     }
69 
70     /**
71      * Handles changes in device orientation. Notifies InCallPresenter of orientation changes.
72      *
73      * Note that this API receives sensor rotation in degrees as a param and we convert that to
74      * one of our screen orientation constants - (one of: {@link SCREEN_ORIENTATION_0},
75      * {@link SCREEN_ORIENTATION_90}, {@link SCREEN_ORIENTATION_180},
76      * {@link SCREEN_ORIENTATION_270}).
77      *
78      * @param rotation The new device sensor rotation in degrees
79      */
80     @Override
onOrientationChanged(int rotation)81     public void onOrientationChanged(int rotation) {
82         if (rotation == OrientationEventListener.ORIENTATION_UNKNOWN) {
83             return;
84         }
85 
86         final int orientation = toScreenOrientation(rotation);
87 
88         if (orientation != SCREEN_ORIENTATION_UNKNOWN && sCurrentOrientation != orientation) {
89             sCurrentOrientation = orientation;
90             InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation);
91         }
92     }
93 
94     /**
95      * Enables the OrientationEventListener and notifies listeners of current orientation if
96      * notify flag is true
97      * @param notify true or false. Notify device orientation changed if true.
98      */
enable(boolean notify)99     public void enable(boolean notify) {
100         super.enable();
101         if (notify) {
102             InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation);
103         }
104     }
105 
106     /**
107      * Enables the OrientationEventListener with notify flag defaulting to false.
108      */
enable()109     public void enable() {
110         enable(false);
111     }
112 
113     /**
114      * Converts sensor rotation in degrees to screen orientation constants.
115      * @param rotation sensor rotation angle in degrees
116      * @return Screen orientation angle in degrees (0, 90, 180, 270). Returns -1 for degrees not
117      * within threshold to identify zones where orientation change should not be trigerred.
118      */
toScreenOrientation(int rotation)119     private int toScreenOrientation(int rotation) {
120         // Sensor orientation 90 is equivalent to screen orientation 270 and vice versa. This
121         // function returns the screen orientation. So we convert sensor rotation 90 to 270 and
122         // vice versa here.
123         if (isInLeftRange(rotation, SCREEN_ORIENTATION_360, ROTATION_THRESHOLD) ||
124                 isInRightRange(rotation, SCREEN_ORIENTATION_0, ROTATION_THRESHOLD)) {
125             return SCREEN_ORIENTATION_0;
126         } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_90, ROTATION_THRESHOLD)) {
127             return SCREEN_ORIENTATION_270;
128         } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_180, ROTATION_THRESHOLD)) {
129             return SCREEN_ORIENTATION_180;
130         } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_270, ROTATION_THRESHOLD)) {
131             return SCREEN_ORIENTATION_90;
132         }
133         return SCREEN_ORIENTATION_UNKNOWN;
134     }
135 
isWithinRange(int value, int begin, int end)136     private static boolean isWithinRange(int value, int begin, int end) {
137         return value >= begin && value < end;
138     }
139 
isWithinThreshold(int value, int center, int threshold)140     private static boolean isWithinThreshold(int value, int center, int threshold) {
141         return isWithinRange(value, center - threshold, center + threshold);
142     }
143 
isInLeftRange(int value, int center, int threshold)144     private static boolean isInLeftRange(int value, int center, int threshold) {
145         return isWithinRange(value, center - threshold, center);
146     }
147 
isInRightRange(int value, int center, int threshold)148     private static boolean isInRightRange(int value, int center, int threshold) {
149         return isWithinRange(value, center, center + threshold);
150     }
151 }
152