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.pm.ActivityInfo; 21 import android.support.annotation.IntDef; 22 import android.view.OrientationEventListener; 23 import com.android.dialer.common.LogUtil; 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 27 /** 28 * This class listens to Orientation events and overrides onOrientationChanged which gets invoked 29 * when an orientation change occurs. When that happens, we notify InCallUI registrants of the 30 * change. 31 */ 32 public class InCallOrientationEventListener extends OrientationEventListener { 33 34 public static final int SCREEN_ORIENTATION_0 = 0; 35 public static final int SCREEN_ORIENTATION_90 = 90; 36 public static final int SCREEN_ORIENTATION_180 = 180; 37 public static final int SCREEN_ORIENTATION_270 = 270; 38 public static final int SCREEN_ORIENTATION_360 = 360; 39 40 /** Screen orientation angles one of 0, 90, 180, 270, 360 in degrees. */ 41 @Retention(RetentionPolicy.SOURCE) 42 @IntDef({ 43 SCREEN_ORIENTATION_0, 44 SCREEN_ORIENTATION_90, 45 SCREEN_ORIENTATION_180, 46 SCREEN_ORIENTATION_270, 47 SCREEN_ORIENTATION_360, 48 SCREEN_ORIENTATION_UNKNOWN 49 }) 50 public @interface ScreenOrientation {} 51 52 // We use SCREEN_ORIENTATION_USER so that reverse-portrait is not allowed. 53 public static final int ACTIVITY_PREFERENCE_ALLOW_ROTATION = ActivityInfo.SCREEN_ORIENTATION_USER; 54 55 public static final int ACTIVITY_PREFERENCE_DISALLOW_ROTATION = 56 ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; 57 58 /** 59 * This is to identify dead zones where we won't notify others of orientation changed. Say for e.g 60 * our threshold is x degrees. We will only notify UI when our current rotation is within x 61 * degrees right or left of the screen orientation angles. If it's not within those ranges, we 62 * return SCREEN_ORIENTATION_UNKNOWN and ignore it. 63 */ 64 public static final int SCREEN_ORIENTATION_UNKNOWN = -1; 65 66 // Rotation threshold is 10 degrees. So if the rotation angle is within 10 degrees of any of 67 // the above angles, we will notify orientation changed. 68 private static final int ROTATION_THRESHOLD = 10; 69 70 /** Cache the current rotation of the device. */ 71 @ScreenOrientation private static int currentOrientation = SCREEN_ORIENTATION_0; 72 73 private boolean enabled = false; 74 InCallOrientationEventListener(Context context)75 public InCallOrientationEventListener(Context context) { 76 super(context); 77 } 78 isWithinRange(int value, int begin, int end)79 private static boolean isWithinRange(int value, int begin, int end) { 80 return value >= begin && value < end; 81 } 82 isWithinThreshold(int value, int center, int threshold)83 private static boolean isWithinThreshold(int value, int center, int threshold) { 84 return isWithinRange(value, center - threshold, center + threshold); 85 } 86 isInLeftRange(int value, int center, int threshold)87 private static boolean isInLeftRange(int value, int center, int threshold) { 88 return isWithinRange(value, center - threshold, center); 89 } 90 isInRightRange(int value, int center, int threshold)91 private static boolean isInRightRange(int value, int center, int threshold) { 92 return isWithinRange(value, center, center + threshold); 93 } 94 95 @ScreenOrientation getCurrentOrientation()96 public static int getCurrentOrientation() { 97 return currentOrientation; 98 } 99 100 /** 101 * Handles changes in device orientation. Notifies InCallPresenter of orientation changes. 102 * 103 * <p>Note that this API receives sensor rotation in degrees as a param and we convert that to one 104 * of our screen orientation constants - (one of: {@link #SCREEN_ORIENTATION_0}, {@link 105 * #SCREEN_ORIENTATION_90}, {@link #SCREEN_ORIENTATION_180}, {@link #SCREEN_ORIENTATION_270}). 106 * 107 * @param rotation The new device sensor rotation in degrees 108 */ 109 @Override onOrientationChanged(int rotation)110 public void onOrientationChanged(int rotation) { 111 if (rotation == OrientationEventListener.ORIENTATION_UNKNOWN) { 112 return; 113 } 114 115 final int orientation = toScreenOrientation(rotation); 116 117 if (orientation != SCREEN_ORIENTATION_UNKNOWN && currentOrientation != orientation) { 118 LogUtil.i( 119 "InCallOrientationEventListener.onOrientationChanged", 120 "orientation: %d -> %d", 121 currentOrientation, 122 orientation); 123 currentOrientation = orientation; 124 InCallPresenter.getInstance().onDeviceOrientationChange(currentOrientation); 125 } 126 } 127 128 /** 129 * Enables the OrientationEventListener and optionally notifies listeners of the current 130 * orientation. 131 * 132 * @param notifyDeviceOrientationChange Whether to notify listeners that the device orientation is 133 * changed. 134 */ enable(boolean notifyDeviceOrientationChange)135 public void enable(boolean notifyDeviceOrientationChange) { 136 if (enabled) { 137 Log.v(this, "enable: Orientation listener is already enabled. Ignoring..."); 138 return; 139 } 140 141 super.enable(); 142 enabled = true; 143 if (notifyDeviceOrientationChange) { 144 InCallPresenter.getInstance().onDeviceOrientationChange(currentOrientation); 145 } 146 } 147 148 /** Enables the OrientationEventListener. */ 149 @Override enable()150 public void enable() { 151 enable(false /* notifyDeviceOrientationChange */); 152 } 153 154 /** Disables the OrientationEventListener. */ 155 @Override disable()156 public void disable() { 157 if (!enabled) { 158 Log.v(this, "enable: Orientation listener is already disabled. Ignoring..."); 159 return; 160 } 161 162 enabled = false; 163 super.disable(); 164 } 165 166 /** Returns true the OrientationEventListener is enabled, false otherwise. */ isEnabled()167 public boolean isEnabled() { 168 return enabled; 169 } 170 171 /** 172 * Converts sensor rotation in degrees to screen orientation constants. 173 * 174 * @param rotation sensor rotation angle in degrees 175 * @return Screen orientation angle in degrees (0, 90, 180, 270). Returns -1 for degrees not 176 * within threshold to identify zones where orientation change should not be trigerred. 177 */ 178 @ScreenOrientation toScreenOrientation(int rotation)179 private int toScreenOrientation(int rotation) { 180 // Sensor orientation 90 is equivalent to screen orientation 270 and vice versa. This 181 // function returns the screen orientation. So we convert sensor rotation 90 to 270 and 182 // vice versa here. 183 if (isInLeftRange(rotation, SCREEN_ORIENTATION_360, ROTATION_THRESHOLD) 184 || isInRightRange(rotation, SCREEN_ORIENTATION_0, ROTATION_THRESHOLD)) { 185 return SCREEN_ORIENTATION_0; 186 } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_90, ROTATION_THRESHOLD)) { 187 return SCREEN_ORIENTATION_270; 188 } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_180, ROTATION_THRESHOLD)) { 189 return SCREEN_ORIENTATION_180; 190 } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_270, ROTATION_THRESHOLD)) { 191 return SCREEN_ORIENTATION_90; 192 } 193 return SCREEN_ORIENTATION_UNKNOWN; 194 } 195 } 196