From 70c216c16d28552d851aadcc0bf6928522f0da6b Mon Sep 17 00:00:00 2001 From: Nivedita Sarkar Date: Thu, 21 May 2015 16:13:14 -0700 Subject: IMS-VT: Listen to sensor orientation changes and update camera preview - Register to listen to OrientationEventListener - Notify registrants of orientation changes and update camera preview size and orientation based on that. - Enable the orientation listener only when CVO is enabled. - Enable the orientation listener for video calls only. Disable it if we downgrade to VOLTE Bug: 21587367 Change-Id: Id1288ee05fe02ebcfee57e52da060ec5c48ceaac --- .../src/com/android/incallui/InCallActivity.java | 77 +++-------- .../incallui/InCallOrientationEventListener.java | 151 +++++++++++++++++++++ .../src/com/android/incallui/InCallPresenter.java | 67 +++------ .../com/android/incallui/VideoCallFragment.java | 27 ++++ .../com/android/incallui/VideoCallPresenter.java | 43 +++--- 5 files changed, 240 insertions(+), 125 deletions(-) create mode 100644 InCallUI/src/com/android/incallui/InCallOrientationEventListener.java (limited to 'InCallUI') diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java index a807a12ea..3dc2c9daf 100644 --- a/InCallUI/src/com/android/incallui/InCallActivity.java +++ b/InCallUI/src/com/android/incallui/InCallActivity.java @@ -90,6 +90,7 @@ public class InCallActivity extends TransactionSafeActivity implements FragmentD private FragmentManager mChildFragmentManager; private AlertDialog mDialog; + private InCallOrientationEventListener mInCallOrientationEventListener; /** * Use to pass 'showDialpad' from {@link #onNewIntent} to {@link #onResume} @@ -146,11 +147,6 @@ public class InCallActivity extends TransactionSafeActivity implements FragmentD */ private OrientationEventListener mOrientationEventListener; - /** - * Used to determine if a change in rotation has occurred. - */ - private static int sPreviousRotation = -1; - @Override protected void onCreate(Bundle icicle) { Log.d(this, "onCreate()... this = " + this); @@ -218,41 +214,7 @@ public class InCallActivity extends TransactionSafeActivity implements FragmentD } } - mOrientationEventListener = new OrientationEventListener(this, - SensorManager.SENSOR_DELAY_NORMAL) { - @Override - public void onOrientationChanged(int orientation) { - // Device is flat, don't change orientation. - if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) { - return; - } - - int newRotation; - // We only shift if we're within 22.5 (23) degrees of the target - // orientation. This avoids flopping back and forth when holding - // the device at 45 degrees or so. - if (orientation >= 337 || orientation <= 23) { - newRotation = Surface.ROTATION_0; - } else if (orientation >= 67 && orientation <= 113) { - // Why not 90? Because screen and sensor orientation are - // reversed. - newRotation = Surface.ROTATION_270; - } else if (orientation >= 157 && orientation <= 203) { - newRotation = Surface.ROTATION_180; - } else if (orientation >= 247 && orientation <= 293) { - newRotation = Surface.ROTATION_90; - } else { - // Device is between orientations, so leave orientation the same. - return; - } - - // Orientation is the current device orientation in degrees. Ultimately we want - // the rotation (in fixed 90 degree intervals). - if (newRotation != sPreviousRotation) { - doOrientationChanged(newRotation); - } - } - }; + mInCallOrientationEventListener = new InCallOrientationEventListener(this); Log.d(this, "onCreate(): exit"); } @@ -283,6 +245,8 @@ public class InCallActivity extends TransactionSafeActivity implements FragmentD // setting activity should be last thing in setup process InCallPresenter.getInstance().setActivity(this); + enableInCallOrientationEventListener(getRequestedOrientation() == + InCallOrientationEventListener.FULL_SENSOR_SCREEN_ORIENTATION); InCallPresenter.getInstance().onActivityStarted(); } @@ -331,6 +295,7 @@ public class InCallActivity extends TransactionSafeActivity implements FragmentD @Override protected void onStop() { Log.d(this, "onStop()..."); + enableInCallOrientationEventListener(false); InCallPresenter.getInstance().updateIsChangingConfigurations(); InCallPresenter.getInstance().onActivityStopped(); mOrientationEventListener.disable(); @@ -547,25 +512,6 @@ public class InCallActivity extends TransactionSafeActivity implements FragmentD return false; } - /** - * Handles changes in device rotation. - * - * @param rotation The new device rotation (one of: {@link Surface#ROTATION_0}, - * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180}, - * {@link Surface#ROTATION_270}). - */ - private void doOrientationChanged(int rotation) { - Log.d(this, "doOrientationChanged prevOrientation=" + sPreviousRotation + - " newOrientation=" + rotation); - // Check to see if the rotation changed to prevent triggering rotation change events - // for other configuration changes. - if (rotation != sPreviousRotation) { - sPreviousRotation = rotation; - InCallPresenter.getInstance().onDeviceRotationChange(rotation); - InCallPresenter.getInstance().onDeviceOrientationChange(sPreviousRotation); - } - } - public CallButtonFragment getCallButtonFragment() { return mCallButtonFragment; } @@ -944,4 +890,17 @@ public class InCallActivity extends TransactionSafeActivity implements FragmentD public void setDispatchTouchEventListener(OnTouchListener mDispatchTouchEventListener) { this.mDispatchTouchEventListener = mDispatchTouchEventListener; } + + /** + * Enables the OrientationEventListener if enable flag is true. Disables it if enable is + * false + * @param enable true or false. + */ + public void enableInCallOrientationEventListener(boolean enable) { + if (enable) { + mInCallOrientationEventListener.enable(enable); + } else { + mInCallOrientationEventListener.disable(); + } + } } diff --git a/InCallUI/src/com/android/incallui/InCallOrientationEventListener.java b/InCallUI/src/com/android/incallui/InCallOrientationEventListener.java new file mode 100644 index 000000000..d3334a3ef --- /dev/null +++ b/InCallUI/src/com/android/incallui/InCallOrientationEventListener.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.incallui; + +import android.content.Context; +import android.content.res.Configuration; +import android.view.OrientationEventListener; +import android.hardware.SensorManager; +import android.view.Surface; +import android.content.pm.ActivityInfo; + +/** + * This class listens to Orientation events and overrides onOrientationChanged which gets + * invoked when an orientation change occurs. When that happens, we notify InCallUI registrants + * of the change. + */ +public class InCallOrientationEventListener extends OrientationEventListener { + + /** + * Screen orientation angles one of 0, 90, 180, 270, 360 in degrees. + */ + public static int SCREEN_ORIENTATION_0 = 0; + public static int SCREEN_ORIENTATION_90 = 90; + public static int SCREEN_ORIENTATION_180 = 180; + public static int SCREEN_ORIENTATION_270 = 270; + public static int SCREEN_ORIENTATION_360 = 360; + + public static int FULL_SENSOR_SCREEN_ORIENTATION = + ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR; + + public static int NO_SENSOR_SCREEN_ORIENTATION = + ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + + /** + * This is to identify dead zones where we won't notify others of orientation changed. + * Say for e.g our threshold is x degrees. We will only notify UI when our current rotation is + * within x degrees right or left of the screen orientation angles. If it's not within those + * ranges, we return SCREEN_ORIENTATION_UNKNOWN and ignore it. + */ + private static int SCREEN_ORIENTATION_UNKNOWN = -1; + + // Rotation threshold is 10 degrees. So if the rotation angle is within 10 degrees of any of + // the above angles, we will notify orientation changed. + private static int ROTATION_THRESHOLD = 10; + + + /** + * Cache the current rotation of the device. + */ + private static int sCurrentOrientation = SCREEN_ORIENTATION_0; + + public InCallOrientationEventListener(Context context) { + super(context); + } + + /** + * Handles changes in device orientation. Notifies InCallPresenter of orientation changes. + * + * Note that this API receives sensor rotation in degrees as a param and we convert that to + * one of our screen orientation constants - (one of: {@link SCREEN_ORIENTATION_0}, + * {@link SCREEN_ORIENTATION_90}, {@link SCREEN_ORIENTATION_180}, + * {@link SCREEN_ORIENTATION_270}). + * + * @param rotation The new device sensor rotation in degrees + */ + @Override + public void onOrientationChanged(int rotation) { + if (rotation == OrientationEventListener.ORIENTATION_UNKNOWN) { + return; + } + + final int orientation = toScreenOrientation(rotation); + + if (orientation != SCREEN_ORIENTATION_UNKNOWN && sCurrentOrientation != orientation) { + sCurrentOrientation = orientation; + InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation); + } + } + + /** + * Enables the OrientationEventListener and notifies listeners of current orientation if + * notify flag is true + * @param notify true or false. Notify device orientation changed if true. + */ + public void enable(boolean notify) { + super.enable(); + if (notify) { + InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation); + } + } + + /** + * Enables the OrientationEventListener with notify flag defaulting to false. + */ + public void enable() { + enable(false); + } + + /** + * Converts sensor rotation in degrees to screen orientation constants. + * @param rotation sensor rotation angle in degrees + * @return Screen orientation angle in degrees (0, 90, 180, 270). Returns -1 for degrees not + * within threshold to identify zones where orientation change should not be trigerred. + */ + private int toScreenOrientation(int rotation) { + // Sensor orientation 90 is equivalent to screen orientation 270 and vice versa. This + // function returns the screen orientation. So we convert sensor rotation 90 to 270 and + // vice versa here. + if (isInLeftRange(rotation, SCREEN_ORIENTATION_360, ROTATION_THRESHOLD) || + isInRightRange(rotation, SCREEN_ORIENTATION_0, ROTATION_THRESHOLD)) { + return SCREEN_ORIENTATION_0; + } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_90, ROTATION_THRESHOLD)) { + return SCREEN_ORIENTATION_270; + } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_180, ROTATION_THRESHOLD)) { + return SCREEN_ORIENTATION_180; + } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_270, ROTATION_THRESHOLD)) { + return SCREEN_ORIENTATION_90; + } + return SCREEN_ORIENTATION_UNKNOWN; + } + + private static boolean isWithinRange(int value, int begin, int end) { + return value >= begin && value < end; + } + + private static boolean isWithinThreshold(int value, int center, int threshold) { + return isWithinRange(value, center - threshold, center + threshold); + } + + private static boolean isInLeftRange(int value, int center, int threshold) { + return isWithinRange(value, center - threshold, center); + } + + private static boolean isInRightRange(int value, int center, int threshold) { + return isWithinRange(value, center, center + threshold); + } +} diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java index c8fe0cb77..836c9242e 100644 --- a/InCallUI/src/com/android/incallui/InCallPresenter.java +++ b/InCallUI/src/com/android/incallui/InCallPresenter.java @@ -1525,64 +1525,32 @@ public class InCallPresenter implements CallList.Listener, } /** - * Handles changes to the device rotation. + * Notifies listeners of changes in orientation and notify calls of rotation angle change. * - * @param rotation The device rotation (one of: {@link Surface#ROTATION_0}, - * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180}, - * {@link Surface#ROTATION_270}). + * @param orientation The screen orientation of the device (one of: + * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_0}, + * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_90}, + * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_180}, + * {@link InCallOrientationEventListener#SCREEN_ORIENTATION_270}). */ - public void onDeviceRotationChange(int rotation) { - Log.d(this, "onDeviceRotationChange: rotation=" + rotation); - // First translate to rotation in degrees. + public void onDeviceOrientationChange(int orientation) { + Log.d(this, "onDeviceOrientationChange: orientation= " + orientation); + if (mCallList != null) { - mCallList.notifyCallsOfDeviceRotation(toRotationAngle(rotation)); + mCallList.notifyCallsOfDeviceRotation(orientation); } else { - Log.w(this, "onDeviceRotationChange: CallList is null."); + Log.w(this, "onDeviceOrientationChange: CallList is null."); } - } - /** - * Converts rotation constants to rotation in degrees. - * @param rotation Rotation constants (one of: {@link Surface#ROTATION_0}, - * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180}, - * {@link Surface#ROTATION_270}). - */ - public static int toRotationAngle(int rotation) { - int rotationAngle; - switch (rotation) { - case Surface.ROTATION_0: - rotationAngle = 0; - break; - case Surface.ROTATION_90: - rotationAngle = 90; - break; - case Surface.ROTATION_180: - rotationAngle = 180; - break; - case Surface.ROTATION_270: - rotationAngle = 270; - break; - default: - rotationAngle = 0; - } - return rotationAngle; - } - - /** - * Notifies listeners of changes in orientation (e.g. portrait/landscape). - * - * @param orientation The orientation of the device (one of: {@link Surface#ROTATION_0}, - * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180}, - * {@link Surface#ROTATION_270}). - */ - public void onDeviceOrientationChange(int orientation) { + // Notify listeners of device orientation changed. for (InCallOrientationListener listener : mOrientationListeners) { listener.onDeviceOrientationChanged(orientation); } } /** - * Configures the in-call UI activity so it can change orientations or not. + * Configures the in-call UI activity so it can change orientations or not. Enables the + * orientation event listener if allowOrientationChange is true, disables it if false. * * @param allowOrientationChange {@code True} if the in-call UI can change between portrait * and landscape. {@Code False} if the in-call UI should be locked in portrait. @@ -1594,12 +1562,15 @@ public class InCallPresenter implements CallList.Listener, } if (!allowOrientationChange) { - mInCallActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); + mInCallActivity.setRequestedOrientation( + InCallOrientationEventListener.NO_SENSOR_SCREEN_ORIENTATION); } else { // Using SCREEN_ORIENTATION_FULL_SENSOR allows for reverse-portrait orientation, where // SCREEN_ORIENTATION_SENSOR does not. - mInCallActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); + mInCallActivity.setRequestedOrientation( + InCallOrientationEventListener.FULL_SENSOR_SCREEN_ORIENTATION); } + mInCallActivity.enableInCallOrientationEventListener(allowOrientationChange); } public void enableScreenTimeout(boolean enable) { diff --git a/InCallUI/src/com/android/incallui/VideoCallFragment.java b/InCallUI/src/com/android/incallui/VideoCallFragment.java index eca9ab883..7c83f6e7e 100644 --- a/InCallUI/src/com/android/incallui/VideoCallFragment.java +++ b/InCallUI/src/com/android/incallui/VideoCallFragment.java @@ -697,6 +697,33 @@ public class VideoCallFragment extends BaseFragment