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 sCurrentOrientation = SCREEN_ORIENTATION_0; 72 73 private boolean mEnabled = false; 74 75 public InCallOrientationEventListener(Context context) { 76 super(context); 77 } 78 79 private static boolean isWithinRange(int value, int begin, int end) { 80 return value >= begin && value < end; 81 } 82 83 private static boolean isWithinThreshold(int value, int center, int threshold) { 84 return isWithinRange(value, center - threshold, center + threshold); 85 } 86 87 private static boolean isInLeftRange(int value, int center, int threshold) { 88 return isWithinRange(value, center - threshold, center); 89 } 90 91 private static boolean isInRightRange(int value, int center, int threshold) { 92 return isWithinRange(value, center, center + threshold); 93 } 94 95 @ScreenOrientation 96 public static int getCurrentOrientation() { 97 return sCurrentOrientation; 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 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 && sCurrentOrientation != orientation) { 118 LogUtil.i( 119 "InCallOrientationEventListener.onOrientationChanged", 120 "orientation: %d -> %d", 121 sCurrentOrientation, 122 orientation); 123 sCurrentOrientation = orientation; 124 InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation); 125 } 126 } 127 128 /** 129 * Enables the OrientationEventListener and notifies listeners of current orientation if notify 130 * flag is true 131 * 132 * @param notify true or false. Notify device orientation changed if true. 133 */ 134 public void enable(boolean notify) { 135 if (mEnabled) { 136 Log.v(this, "enable: Orientation listener is already enabled. Ignoring..."); 137 return; 138 } 139 140 super.enable(); 141 mEnabled = true; 142 if (notify) { 143 InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation); 144 } 145 } 146 147 /** Enables the OrientationEventListener with notify flag defaulting to false. */ 148 @Override 149 public void enable() { 150 enable(false); 151 } 152 153 /** Disables the OrientationEventListener. */ 154 @Override 155 public void disable() { 156 if (!mEnabled) { 157 Log.v(this, "enable: Orientation listener is already disabled. Ignoring..."); 158 return; 159 } 160 161 mEnabled = false; 162 super.disable(); 163 } 164 165 /** Returns true the OrientationEventListener is enabled, false otherwise. */ 166 public boolean isEnabled() { 167 return mEnabled; 168 } 169 170 /** 171 * Converts sensor rotation in degrees to screen orientation constants. 172 * 173 * @param rotation sensor rotation angle in degrees 174 * @return Screen orientation angle in degrees (0, 90, 180, 270). Returns -1 for degrees not 175 * within threshold to identify zones where orientation change should not be trigerred. 176 */ 177 @ScreenOrientation 178 private int toScreenOrientation(int rotation) { 179 // Sensor orientation 90 is equivalent to screen orientation 270 and vice versa. This 180 // function returns the screen orientation. So we convert sensor rotation 90 to 270 and 181 // vice versa here. 182 if (isInLeftRange(rotation, SCREEN_ORIENTATION_360, ROTATION_THRESHOLD) 183 || isInRightRange(rotation, SCREEN_ORIENTATION_0, ROTATION_THRESHOLD)) { 184 return SCREEN_ORIENTATION_0; 185 } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_90, ROTATION_THRESHOLD)) { 186 return SCREEN_ORIENTATION_270; 187 } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_180, ROTATION_THRESHOLD)) { 188 return SCREEN_ORIENTATION_180; 189 } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_270, ROTATION_THRESHOLD)) { 190 return SCREEN_ORIENTATION_90; 191 } 192 return SCREEN_ORIENTATION_UNKNOWN; 193 } 194 } 195