Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5439f22 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #3041660: Camera image flips upside down when rotating device

Apps now must explicitly opt in to having their rotation changed while
forcing landscape mode.  Also add some new orientation constants for other
things apps may want to do.

Change-Id: If64d84b5ef54793ee717ebda9b4c76408efc9bfd
parent 407f625a
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -46755,6 +46755,17 @@
 visibility="public"
>
</field>
<field name="SCREEN_ORIENTATION_FULL_SENSOR"
 type="int"
 transient="false"
 volatile="false"
 value="10"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="SCREEN_ORIENTATION_LANDSCAPE"
 type="int"
 transient="false"
@@ -46788,6 +46799,28 @@
 visibility="public"
>
</field>
<field name="SCREEN_ORIENTATION_REVERSE_LANDSCAPE"
 type="int"
 transient="false"
 volatile="false"
 value="8"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="SCREEN_ORIENTATION_REVERSE_PORTRAIT"
 type="int"
 transient="false"
 volatile="false"
 value="9"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="SCREEN_ORIENTATION_SENSOR"
 type="int"
 transient="false"
@@ -46799,6 +46832,28 @@
 visibility="public"
>
</field>
<field name="SCREEN_ORIENTATION_SENSOR_LANDSCAPE"
 type="int"
 transient="false"
 volatile="false"
 value="6"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="SCREEN_ORIENTATION_SENSOR_PORTRAIT"
 type="int"
 transient="false"
 volatile="false"
 value="7"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="SCREEN_ORIENTATION_UNSPECIFIED"
 type="int"
 transient="false"
+38 −2
Original line number Diff line number Diff line
@@ -194,10 +194,41 @@ public class ActivityInfo extends ComponentInfo
    public static final int SCREEN_ORIENTATION_SENSOR = 4;
  
    /**
     * Constant corresponding to <code>sensor</code> in
     * Constant corresponding to <code>nosensor</code> in
     * the {@link android.R.attr#screenOrientation} attribute.
     */
    public static final int SCREEN_ORIENTATION_NOSENSOR = 5;

    /**
     * Constant corresponding to <code>sensorLandscape</code> in
     * the {@link android.R.attr#screenOrientation} attribute.
     */
    public static final int SCREEN_ORIENTATION_SENSOR_LANDSCAPE = 6;

    /**
     * Constant corresponding to <code>sensorPortrait</code> in
     * the {@link android.R.attr#screenOrientation} attribute.
     */
    public static final int SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7;

    /**
     * Constant corresponding to <code>reverseLandscape</code> in
     * the {@link android.R.attr#screenOrientation} attribute.
     */
    public static final int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;

    /**
     * Constant corresponding to <code>reversePortrait</code> in
     * the {@link android.R.attr#screenOrientation} attribute.
     */
    public static final int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;

    /**
     * Constant corresponding to <code>fullSensor</code> in
     * the {@link android.R.attr#screenOrientation} attribute.
     */
    public static final int SCREEN_ORIENTATION_FULL_SENSOR = 10;

    /**
     * The preferred screen orientation this activity would like to run in.
     * From the {@link android.R.attr#screenOrientation} attribute, one of
@@ -207,7 +238,12 @@ public class ActivityInfo extends ComponentInfo
     * {@link #SCREEN_ORIENTATION_USER},
     * {@link #SCREEN_ORIENTATION_BEHIND},
     * {@link #SCREEN_ORIENTATION_SENSOR},
     * {@link #SCREEN_ORIENTATION_NOSENSOR}.
     * {@link #SCREEN_ORIENTATION_NOSENSOR},
     * {@link #SCREEN_ORIENTATION_SENSOR_LANDSCAPE},
     * {@link #SCREEN_ORIENTATION_SENSOR_PORTRAIT},
     * {@link #SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
     * {@link #SCREEN_ORIENTATION_REVERSE_PORTRAIT},
     * {@link #SCREEN_ORIENTATION_FULL_SENSOR}.
     */
    public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
    
+49 −10
Original line number Diff line number Diff line
@@ -28,6 +28,11 @@ import android.util.Log;
 * A special helper class used by the WindowManager
 *  for receiving notifications from the SensorManager when
 * the orientation of the device has changed.
 *
 * NOTE: If changing anything here, please run the API demo
 * "App/Activity/Screen Orientation" to ensure that all orientation
 * modes still work correctly.
 *
 * @hide
 */
public abstract class WindowOrientationListener {
@@ -103,6 +108,10 @@ public abstract class WindowOrientationListener {
        }
    }

    public void setAllow180Rotation(boolean allowed) {
        mSensorEventListener.setAllow180Rotation(allowed);
    }

    public int getCurrentRotation(int lastRotation) {
        if (mEnabled) {
            return mSensorEventListener.getCurrentRotation(lastRotation);
@@ -151,19 +160,20 @@ public abstract class WindowOrientationListener {
        private static final int ROTATION_0 = 0;
        private static final int ROTATION_90 = 1;
        private static final int ROTATION_270 = 2;
        private static final int ROTATION_180 = 3;

        // Mapping our internal aliases into actual Surface rotation values
        private static final int[] INTERNAL_TO_SURFACE_ROTATION = new int[] {
            Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_270};
            Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_270,
            Surface.ROTATION_180};

        // Mapping Surface rotation values to internal aliases.
        // We have no constant for Surface.ROTATION_180.  That should never happen, but if it
        // does, we'll arbitrarily choose a mapping.
        private static final int[] SURFACE_TO_INTERNAL_ROTATION = new int[] {
            ROTATION_0, ROTATION_90, ROTATION_90, ROTATION_270};
            ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270};

        // Threshold ranges of orientation angle to transition into other orientation states.
        // The first list is for transitions from ROTATION_0, the next for ROTATION_90, etc.
        // The first list is for transitions from ROTATION_0, ROTATION_90, ROTATION_270,
        // and then ROTATION_180.
        // ROTATE_TO defines the orientation each threshold range transitions to, and must be kept
        // in sync with this.
        // We generally transition about the halfway point between two states with a swing of 30
@@ -172,13 +182,32 @@ public abstract class WindowOrientationListener {
                {{60, 180}, {180, 300}},
                {{0, 30}, {195, 315}, {315, 360}},
                {{0, 45}, {45, 165}, {330, 360}},
        };

                // Handle situation where we are currently doing 180 rotation
                // but that is no longer allowed.
                {{0, 45}, {45, 135}, {135, 225}, {225, 315}, {315, 360}},
        };
        // See THRESHOLDS
        private static final int[][] ROTATE_TO = new int[][] {
                {ROTATION_90, ROTATION_270},
                {ROTATION_0, ROTATION_270, ROTATION_0},
                {ROTATION_0, ROTATION_90, ROTATION_0},
                {ROTATION_0, ROTATION_90, ROTATION_0, ROTATION_270, ROTATION_0},
        };

        // Thresholds that allow all 4 orientations.
        private static final int[][][] THRESHOLDS_WITH_180 = new int[][][] {
            {{60, 165}, {165, 195}, {195, 300}},
            {{0, 30}, {165, 195}, {195, 315}, {315, 360}},
            {{0, 45}, {45, 165}, {165, 195}, {330, 360}},
            {{0, 45}, {45, 135}, {225, 315}, {315, 360}},
        };
        // See THRESHOLDS_WITH_180
        private static final int[][] ROTATE_TO_WITH_180 = new int[][] {
            {ROTATION_90, ROTATION_180, ROTATION_270},
            {ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0},
            {ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},
            {ROTATION_0, ROTATION_90, ROTATION_270, ROTATION_0},
        };

        // Maximum absolute tilt angle at which to consider orientation data.  Beyond this (i.e.
@@ -188,7 +217,7 @@ public abstract class WindowOrientationListener {
        // Additional limits on tilt angle to transition to each new orientation.  We ignore all
        // data with tilt beyond MAX_TILT, but we can set stricter limits on transitions to a
        // particular orientation here.
        private static final int[] MAX_TRANSITION_TILT = new int[] {MAX_TILT, 65, 65};
        private static final int[] MAX_TRANSITION_TILT = new int[] {MAX_TILT, 65, 65, 40};

        // Between this tilt angle and MAX_TILT, we'll allow orientation changes, but we'll filter
        // with a higher time constant, making us less sensitive to change.  This primarily helps
@@ -228,6 +257,8 @@ public abstract class WindowOrientationListener {
        private static final float ACCELERATING_LOWPASS_ALPHA =
            computeLowpassAlpha(ACCELERATING_TIME_CONSTANT_MS);

        private boolean mAllow180Rotation = false;

        private WindowOrientationListener mOrientationListener;
        private int mRotation = ROTATION_0; // Current orientation state
        private float mTiltAngle = 0; // low-pass filtered
@@ -249,6 +280,10 @@ public abstract class WindowOrientationListener {
            return (float) SAMPLING_PERIOD_MS / (timeConstantMs + SAMPLING_PERIOD_MS);
        }

        void setAllow180Rotation(boolean allowed) {
            mAllow180Rotation = allowed;
        }

        int getCurrentRotation(int lastRotation) {
            if (mTiltDistrust > 0) {
                // we really don't know the current orientation, so trust what's currently displayed
@@ -259,7 +294,9 @@ public abstract class WindowOrientationListener {

        private void calculateNewRotation(float orientation, float tiltAngle) {
            if (localLOGV) Log.i(TAG, orientation + ", " + tiltAngle + ", " + mRotation);
            int thresholdRanges[][] = THRESHOLDS[mRotation];
            final boolean allow180Rotation = mAllow180Rotation;
            int thresholdRanges[][] = allow180Rotation
                    ? THRESHOLDS_WITH_180[mRotation] : THRESHOLDS[mRotation];
            int row = -1;
            for (int i = 0; i < thresholdRanges.length; i++) {
                if (orientation >= thresholdRanges[i][0] && orientation < thresholdRanges[i][1]) {
@@ -269,13 +306,15 @@ public abstract class WindowOrientationListener {
            }
            if (row == -1) return; // no matching transition

            int rotation = ROTATE_TO[mRotation][row];
            int rotation = allow180Rotation
                    ? ROTATE_TO_WITH_180[mRotation][row] : ROTATE_TO[mRotation][row];
            if (tiltAngle > MAX_TRANSITION_TILT[rotation]) {
                // tilted too far flat to go to this rotation
                return;
            }

            if (localLOGV) Log.i(TAG, " new rotation = " + rotation);
            if (localLOGV) Log.i(TAG, "orientation " + orientation + " gives new rotation = "
                    + rotation);
            mRotation = rotation;
            mOrientationListener.onOrientationChanged(INTERNAL_TO_SURFACE_ROTATION[mRotation]);
        }
+20 −2
Original line number Diff line number Diff line
@@ -495,10 +495,10 @@
             orientation will changed based on how the user rotates the device -->
        <enum name="unspecified" value="-1" />
        <!-- Would like to have the screen in a landscape orientation: that
             is, with the display wider than it is tall. -->
             is, with the display wider than it is tall, ignoring sensor data. -->
        <enum name="landscape" value="0" />
        <!-- Would like to have the screen in a portrait orientation: that
             is, with the display taller than it is wide. -->
             is, with the display taller than it is wide, ignoring sensor data. -->
        <enum name="portrait" value="1" />
        <!-- Use the user's current preferred orientation of the handset. -->
        <enum name="user" value="2" />
@@ -511,6 +511,24 @@
        <!-- Always ignore orientation determined by orientation sensor:
             the display will not rotate when the user moves the device. -->
        <enum name="nosensor" value="5" />
        <!-- Would like to have the screen in landscape orientation, but can
             use the sensor to change which direction the screen is facing. -->
        <enum name="sensorLandscape" value="6" />
        <!-- Would like to have the screen in portrait orientation, but can
             use the sensor to change which direction the screen is facing. -->
        <enum name="sensorPortait" value="7" />
        <!-- Would like to have the screen in landscape orientation, turned in
             the opposite direction from normal landscape. -->
        <enum name="reverseLandscape" value="8" />
        <!-- Would like to have the screen in portrait orientation, turned in
             the opposite direction from normal portrait. -->
        <enum name="reversePortait" value="9" />
        <!-- Orientation is determined by a physical orientation sensor:
             the display will rotate based on how the user moves the device.
             This allows any of the 4 possible rotations, regardless of what
             the device will normally do (for example some devices won't
             normally use 180 degree rotation). -->
        <enum name="fullSensor" value="10" />
    </attr>
    
    <!-- Specify one or more configuration changes that the activity will
+60 −22
Original line number Diff line number Diff line
@@ -288,7 +288,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {

    int mLandscapeRotation = -1; // default landscape rotation
    int mSeascapeRotation = -1; // "other" landscape rotation, 180 degrees from mLandscapeRotation
    int mPortraitRotation = -1;
    int mPortraitRotation = -1; // default portrait rotation
    int mUpsideDownRotation = -1; // "other" portrait rotation

    // Nothing to see here, move along...
    int mFancyRotationAnimation;
@@ -353,26 +354,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {

    boolean useSensorForOrientationLp(int appOrientation) {
        // The app says use the sensor.
        if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
        if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
                || appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
            return true;
        }
        // The user preference says we can rotate, and the app is willing to rotate.
        // Note we include SCREEN_ORIENTATION_LANDSCAPE since we can use the sensor to choose
        // between the two possible landscape rotations.
        if (mAccelerometerDefault != 0 &&
                (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) {
                 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
            return true;
        }
        // We're in a dock that has a rotation affinity, an the app is willing to rotate.
        // We're in a dock that has a rotation affinity, and the app is willing to rotate.
        if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR)
                || (mDeskDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_DESK)) {
            // Note we override the nosensor flag here.
            if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
                    || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
                return true;
            }
        }
@@ -386,7 +386,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     * screen is switched off.
     */
    boolean needSensorRunningLp() {
        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
            // If the application has explicitly requested to follow the
            // orientation, then we need to turn the sensor or.
            return true;
@@ -2060,21 +2063,42 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            if (d.getWidth() > d.getHeight()) {
                mPortraitRotation = Surface.ROTATION_90;
                mLandscapeRotation = Surface.ROTATION_0;
                mUpsideDownRotation = Surface.ROTATION_270;
                mSeascapeRotation = Surface.ROTATION_180;
            } else {
                mPortraitRotation = Surface.ROTATION_0;
                mLandscapeRotation = Surface.ROTATION_90;
                mUpsideDownRotation = Surface.ROTATION_180;
                mSeascapeRotation = Surface.ROTATION_270;
            }
        }

        synchronized (mLock) {
            if (orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
            switch (orientation) {
                case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
                    //always return portrait if orientation set to portrait
                    return mPortraitRotation;
            } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
                case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
                    //always return landscape if orientation set to landscape
                    return mLandscapeRotation;
                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
                    //always return portrait if orientation set to portrait
                    return mUpsideDownRotation;
                case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
                    //always return seascape if orientation set to reverse landscape
                    return mSeascapeRotation;
                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
                    //return either landscape rotation based on the sensor
                    mOrientationListener.setAllow180Rotation(false);
                    return getCurrentLandscapeRotation(lastRotation);
                case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
                    mOrientationListener.setAllow180Rotation(true);
                    return getCurrentPortraitRotation(lastRotation);
            }

            mOrientationListener.setAllow180Rotation(
                    orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);

            // case for nosensor meaning ignore sensor and consider only lid
            // or orientation sensor disabled
            //or case.unspecified
@@ -2094,18 +2118,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    }

    private int getCurrentLandscapeRotation(int lastRotation) {
        // landscape-only apps can take either landscape rotation
        if (useSensorForOrientationLp(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)) {
        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
        if (isLandscapeOrSeascape(sensorRotation)) {
            return sensorRotation;
        }
        }
        // try to preserve the old rotation if it was landscape
        if (isLandscapeOrSeascape(lastRotation)) {
            return lastRotation;
        }
        // default to one of the two landscape rotations
        // default to one of the primary landscape rotation
        return mLandscapeRotation;
    }

@@ -2113,6 +2134,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        return sensorRotation == mLandscapeRotation || sensorRotation == mSeascapeRotation;
    }

    private int getCurrentPortraitRotation(int lastRotation) {
        int sensorRotation = mOrientationListener.getCurrentRotation(lastRotation);
        if (isAnyPortrait(sensorRotation)) {
            return sensorRotation;
        }
        // try to preserve the old rotation if it was portrait
        if (isAnyPortrait(lastRotation)) {
            return lastRotation;
        }
        // default to one of the primary portrait rotations
        return mPortraitRotation;
    }

    private boolean isAnyPortrait(int sensorRotation) {
        return sensorRotation == mPortraitRotation || sensorRotation == mUpsideDownRotation;
    }

    public boolean detectSafeMode() {
        try {
            int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
Loading