170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar/*
270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * Copyright (C) 2015 The Android Open Source Project
370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar *
470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * Licensed under the Apache License, Version 2.0 (the "License");
570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * you may not use this file except in compliance with the License.
670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * You may obtain a copy of the License at
770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar *
870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar *      http://www.apache.org/licenses/LICENSE-2.0
970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar *
1070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * Unless required by applicable law or agreed to in writing, software
1170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * distributed under the License is distributed on an "AS IS" BASIS,
1270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * See the License for the specific language governing permissions and
1470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * limitations under the License
1570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar */
1670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
1770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkarpackage com.android.incallui;
1870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
1970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkarimport android.content.Context;
2070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkarimport android.content.res.Configuration;
2170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkarimport android.view.OrientationEventListener;
2270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkarimport android.hardware.SensorManager;
2370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkarimport android.view.Surface;
2470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkarimport android.content.pm.ActivityInfo;
2570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
2670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar/**
2770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * This class listens to Orientation events and overrides onOrientationChanged which gets
2870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * invoked when an orientation change occurs. When that happens, we notify InCallUI registrants
2970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar * of the change.
3070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar */
3170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkarpublic class InCallOrientationEventListener extends OrientationEventListener {
3270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
3370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    /**
3470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * Screen orientation angles one of 0, 90, 180, 270, 360 in degrees.
3570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     */
3670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public static int SCREEN_ORIENTATION_0 = 0;
3770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public static int SCREEN_ORIENTATION_90 = 90;
3870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public static int SCREEN_ORIENTATION_180 = 180;
3970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public static int SCREEN_ORIENTATION_270 = 270;
4070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public static int SCREEN_ORIENTATION_360 = 360;
4170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
4270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public static int FULL_SENSOR_SCREEN_ORIENTATION =
4370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
4470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
4570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public static int NO_SENSOR_SCREEN_ORIENTATION =
4670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
4770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
4870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    /**
4970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * This is to identify dead zones where we won't notify others of orientation changed.
5070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * Say for e.g our threshold is x degrees. We will only notify UI when our current rotation is
5170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * within x degrees right or left of the screen orientation angles. If it's not within those
5270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * ranges, we return SCREEN_ORIENTATION_UNKNOWN and ignore it.
5370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     */
5470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    private static int SCREEN_ORIENTATION_UNKNOWN = -1;
5570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
5670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    // Rotation threshold is 10 degrees. So if the rotation angle is within 10 degrees of any of
5770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    // the above angles, we will notify orientation changed.
5870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    private static int ROTATION_THRESHOLD = 10;
5970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
6070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
6170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    /**
6270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * Cache the current rotation of the device.
6370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     */
6470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    private static int sCurrentOrientation = SCREEN_ORIENTATION_0;
6550b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn    private boolean mEnabled = false;
6670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
6770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public InCallOrientationEventListener(Context context) {
6870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        super(context);
6970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    }
7070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
7170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    /**
7270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * Handles changes in device orientation. Notifies InCallPresenter of orientation changes.
7370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     *
7470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * Note that this API receives sensor rotation in degrees as a param and we convert that to
7570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * one of our screen orientation constants - (one of: {@link SCREEN_ORIENTATION_0},
7670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * {@link SCREEN_ORIENTATION_90}, {@link SCREEN_ORIENTATION_180},
7770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * {@link SCREEN_ORIENTATION_270}).
7870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     *
7970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * @param rotation The new device sensor rotation in degrees
8070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     */
8170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    @Override
8270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public void onOrientationChanged(int rotation) {
8370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        if (rotation == OrientationEventListener.ORIENTATION_UNKNOWN) {
8470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            return;
8570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        }
8670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
8770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        final int orientation = toScreenOrientation(rotation);
8870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
8970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        if (orientation != SCREEN_ORIENTATION_UNKNOWN && sCurrentOrientation != orientation) {
9070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            sCurrentOrientation = orientation;
9170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation);
9270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        }
9370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    }
9470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
9570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    /**
9670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * Enables the OrientationEventListener and notifies listeners of current orientation if
9770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * notify flag is true
9870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * @param notify true or false. Notify device orientation changed if true.
9970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     */
10070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public void enable(boolean notify) {
10150b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn        if (mEnabled) {
10250b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn            Log.v(this, "enable: Orientation listener is already enabled. Ignoring...");
10350b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn            return;
10450b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn        }
10550b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn
10670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        super.enable();
10750b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn        mEnabled = true;
10870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        if (notify) {
10970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            InCallPresenter.getInstance().onDeviceOrientationChange(sCurrentOrientation);
11070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        }
11170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    }
11270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
11370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    /**
11470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * Enables the OrientationEventListener with notify flag defaulting to false.
11570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     */
11670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    public void enable() {
11770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        enable(false);
11870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    }
11970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
12070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    /**
12150b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn     * Disables the OrientationEventListener.
12250b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn     */
12350b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn    public void disable() {
12450b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn        if (!mEnabled) {
12550b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn            Log.v(this, "enable: Orientation listener is already disabled. Ignoring...");
12650b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn            return;
12750b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn        }
12850b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn
12950b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn        mEnabled = false;
13050b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn        super.disable();
13150b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn    }
13250b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn
13350b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn    /**
13450b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn     * Returns true the OrientationEventListener is enabled, false otherwise.
13550b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn     */
13650b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn    public boolean isEnabled() {
13750b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn        return mEnabled;
13850b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn    }
13950b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn
14050b2f304bde9bdb8c8c5ca57efafb53a417afa78Tyler Gunn    /**
14170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * Converts sensor rotation in degrees to screen orientation constants.
14270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * @param rotation sensor rotation angle in degrees
14370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * @return Screen orientation angle in degrees (0, 90, 180, 270). Returns -1 for degrees not
14470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     * within threshold to identify zones where orientation change should not be trigerred.
14570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar     */
14670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    private int toScreenOrientation(int rotation) {
14770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        // Sensor orientation 90 is equivalent to screen orientation 270 and vice versa. This
14870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        // function returns the screen orientation. So we convert sensor rotation 90 to 270 and
14970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        // vice versa here.
15070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        if (isInLeftRange(rotation, SCREEN_ORIENTATION_360, ROTATION_THRESHOLD) ||
15170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar                isInRightRange(rotation, SCREEN_ORIENTATION_0, ROTATION_THRESHOLD)) {
15270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            return SCREEN_ORIENTATION_0;
15370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_90, ROTATION_THRESHOLD)) {
15470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            return SCREEN_ORIENTATION_270;
15570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_180, ROTATION_THRESHOLD)) {
15670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            return SCREEN_ORIENTATION_180;
15770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        } else if (isWithinThreshold(rotation, SCREEN_ORIENTATION_270, ROTATION_THRESHOLD)) {
15870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar            return SCREEN_ORIENTATION_90;
15970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        }
16070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        return SCREEN_ORIENTATION_UNKNOWN;
16170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    }
16270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
16370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    private static boolean isWithinRange(int value, int begin, int end) {
16470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        return value >= begin && value < end;
16570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    }
16670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
16770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    private static boolean isWithinThreshold(int value, int center, int threshold) {
16870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        return isWithinRange(value, center - threshold, center + threshold);
16970c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    }
17070c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
17170c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    private static boolean isInLeftRange(int value, int center, int threshold) {
17270c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        return isWithinRange(value, center - threshold, center);
17370c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    }
17470c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar
17570c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    private static boolean isInRightRange(int value, int center, int threshold) {
17670c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar        return isWithinRange(value, center, center + threshold);
17770c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar    }
17870c216c16d28552d851aadcc0bf6928522f0da6bNivedita Sarkar}
179