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

Commit 9e70cef7 authored by Graciela Putri's avatar Graciela Putri Committed by Automerger Merge Worker
Browse files

Merge "Prevent orientation request loop in override" into tm-qpr-dev am: 84903feb am: 28d7f6a5

parents 3049e782 28d7f6a5
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -1086,6 +1086,20 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
    public static final long OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION =
    public static final long OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION =
            254631730L; // buganizer id
            254631730L; // buganizer id


    /**
     * This change id enables compat policy that ignores app requested orientation in
     * response to an app calling {@link android.app.Activity#setRequestedOrientation} more
     * than twice in one second if an activity is not letterboxed for fixed orientation.
     * See com.android.server.wm.LetterboxUiController#shouldIgnoreRequestedOrientation
     * for details.
     * @hide
     */
    @ChangeId
    @Overridable
    @Disabled
    public static final long OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED =
            273509367L; // buganizer id

    /**
    /**
     * This change id forces the packages it is applied to never have Display API sandboxing
     * This change id forces the packages it is applied to never have Display API sandboxing
     * applied for a letterbox or SCM activity. The Display APIs will continue to provide
     * applied for a letterbox or SCM activity. The Display APIs will continue to provide
+84 −14
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FOR
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
@@ -130,6 +131,14 @@ final class LetterboxUiController {


    private static final float UNDEFINED_ASPECT_RATIO = 0f;
    private static final float UNDEFINED_ASPECT_RATIO = 0f;


    // Minimum value of mSetOrientationRequestCounter before qualifying as orientation request loop
    @VisibleForTesting
    static final int MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP = 2;
    // Used to determine reset of mSetOrientationRequestCounter if next app requested
    // orientation is after timeout value
    @VisibleForTesting
    static final int SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS = 1000;

    private final Point mTmpPoint = new Point();
    private final Point mTmpPoint = new Point();


    private final LetterboxConfiguration mLetterboxConfiguration;
    private final LetterboxConfiguration mLetterboxConfiguration;
@@ -162,6 +171,8 @@ final class LetterboxUiController {


    // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
    // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
    private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled;
    private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled;
    // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED
    private final boolean mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled;


    // Corresponds to OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS
    // Corresponds to OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS
    private final boolean mIsOverrideEnableCompatFakeFocusEnabled;
    private final boolean mIsOverrideEnableCompatFakeFocusEnabled;
@@ -186,12 +197,18 @@ final class LetterboxUiController {
    private float mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO;
    private float mInheritedMinAspectRatio = UNDEFINED_ASPECT_RATIO;
    private float mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO;
    private float mInheritedMaxAspectRatio = UNDEFINED_ASPECT_RATIO;


    // Updated when ActivityRecord#setRequestedOrientation is called
    private long mTimeMsLastSetOrientationRequest = 0;

    @Configuration.Orientation
    @Configuration.Orientation
    private int mInheritedOrientation = ORIENTATION_UNDEFINED;
    private int mInheritedOrientation = ORIENTATION_UNDEFINED;


    // The app compat state for the opaque activity if any
    // The app compat state for the opaque activity if any
    private int mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN;
    private int mInheritedAppCompatState = APP_COMPAT_STATE_CHANGED__STATE__UNKNOWN;


    // Counter for ActivityRecord#setRequestedOrientation
    private int mSetOrientationRequestCounter = 0;

    // The CompatDisplayInsets of the opaque activity beneath the translucent one.
    // The CompatDisplayInsets of the opaque activity beneath the translucent one.
    private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets;
    private ActivityRecord.CompatDisplayInsets mInheritedCompatDisplayInsets;


@@ -284,6 +301,9 @@ final class LetterboxUiController {


        mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled =
        mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled =
                isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION);
                isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION);
        mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled =
                isCompatChangeEnabled(
                        OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED);


        mIsOverrideEnableCompatFakeFocusEnabled =
        mIsOverrideEnableCompatFakeFocusEnabled =
                isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS);
                isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS);
@@ -354,20 +374,20 @@ final class LetterboxUiController {
     *     <li>Opt-in component property or per-app override are enabled
     *     <li>Opt-in component property or per-app override are enabled
     *     <li>Activity is relaunched after {@link android.app.Activity#setRequestedOrientation}
     *     <li>Activity is relaunched after {@link android.app.Activity#setRequestedOrientation}
     *     call from an app or camera compat force rotation treatment is active for the activity.
     *     call from an app or camera compat force rotation treatment is active for the activity.
     *     <li>Orientation request loop detected and is not letterboxed for fixed orientation
     * </ul>
     * </ul>
     */
     */
    boolean shouldIgnoreRequestedOrientation(@ScreenOrientation int requestedOrientation) {
    boolean shouldIgnoreRequestedOrientation(@ScreenOrientation int requestedOrientation) {
        if (!shouldEnableWithOverrideAndProperty(
        if (shouldEnableWithOverrideAndProperty(
                /* gatingCondition */ mLetterboxConfiguration
                /* gatingCondition */ mLetterboxConfiguration
                        ::isPolicyForIgnoringRequestedOrientationEnabled,
                        ::isPolicyForIgnoringRequestedOrientationEnabled,
                mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled,
                mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled,
                mBooleanPropertyIgnoreRequestedOrientation)) {
                mBooleanPropertyIgnoreRequestedOrientation)) {
            return false;
        }
            if (mIsRelauchingAfterRequestedOrientationChanged) {
            if (mIsRelauchingAfterRequestedOrientationChanged) {
                Slog.w(TAG, "Ignoring orientation update to "
                Slog.w(TAG, "Ignoring orientation update to "
                        + screenOrientationToString(requestedOrientation)
                        + screenOrientationToString(requestedOrientation)
                    + " due to relaunching after setRequestedOrientation for " + mActivityRecord);
                        + " due to relaunching after setRequestedOrientation for "
                        + mActivityRecord);
                return true;
                return true;
            }
            }
            DisplayContent displayContent = mActivityRecord.mDisplayContent;
            DisplayContent displayContent = mActivityRecord.mDisplayContent;
@@ -382,9 +402,59 @@ final class LetterboxUiController {
                        + " due to camera compat treatment for " + mActivityRecord);
                        + " due to camera compat treatment for " + mActivityRecord);
                return true;
                return true;
            }
            }
        }

        if (shouldIgnoreOrientationRequestLoop()) {
            Slog.w(TAG, "Ignoring orientation update to "
                    + screenOrientationToString(requestedOrientation)
                    + " as orientation request loop was detected for "
                    + mActivityRecord);
            return true;
        }
        return false;
    }

    /**
     * Whether an app is calling {@link android.app.Activity#setRequestedOrientation}
     * in a loop and orientation request should be ignored.
     *
     * <p>This should only be called once in response to
     * {@link android.app.Activity#setRequestedOrientation}. See
     * {@link #shouldIgnoreRequestedOrientation} for more details.
     *
     * <p>This treatment is enabled when the following conditions are met:
     * <ul>
     *     <li>Per-app override is enabled
     *     <li>App has requested orientation more than 2 times within 1-second
     *     timer and activity is not letterboxed for fixed orientation
     * </ul>
     */
    @VisibleForTesting
    boolean shouldIgnoreOrientationRequestLoop() {
        if (!mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled) {
            return false;
            return false;
        }
        }


        final long currTimeMs = System.currentTimeMillis();
        if (currTimeMs - mTimeMsLastSetOrientationRequest
                < SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS) {
            mSetOrientationRequestCounter += 1;
        } else {
            // Resets app setOrientationRequest counter if timed out
            mSetOrientationRequestCounter = 0;
        }
        // Update time last called
        mTimeMsLastSetOrientationRequest = currTimeMs;

        return mSetOrientationRequestCounter >= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP
                && !mActivityRecord.isLetterboxedForFixedOrientationAndAspectRatio();
    }

    @VisibleForTesting
    int getSetOrientationRequestCounter() {
        return mSetOrientationRequestCounter;
    }

    /**
    /**
     * Whether sending compat fake focus for split screen resumed activities is enabled. Needed
     * Whether sending compat fake focus for split screen resumed activities is enabled. Needed
     * because some game engines wait to get focus before drawing the content of the app which isn't
     * because some game engines wait to get focus before drawing the content of the app which isn't
+66 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FOR
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
@@ -46,6 +47,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.LetterboxUiController.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
import static com.android.server.wm.LetterboxUiController.SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertFalse;
@@ -185,6 +188,69 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
        assertFalse(mController.shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
        assertFalse(mController.shouldIgnoreRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED));
    }
    }


    @Test
    public void testShouldIgnoreOrientationRequestLoop_overrideDisabled_returnsFalse() {
        doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
        // Request 3 times to simulate orientation request loop
        for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
            assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
                    /* expectedCount */ 0);
        }
    }

    @Test
    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
    public void testShouldIgnoreOrientationRequestLoop_isLetterboxed_returnsFalse() {
        doReturn(true).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
        // Request 3 times to simulate orientation request loop
        for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
            assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
                    /* expectedCount */ i);
        }
    }

    @Test
    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
    public void testShouldIgnoreOrientationRequestLoop_noLoop_returnsFalse() {
        doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
        // No orientation request loop
        assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
                /* expectedCount */ 0);
    }

    @Test
    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
    public void testShouldIgnoreOrientationRequestLoop_timeout_returnsFalse()
            throws InterruptedException {
        doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
        for (int i = MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i > 0; i--) {
            assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
                    /* expectedCount */ 0);
            Thread.sleep(SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS);
        }
    }

    @Test
    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
    public void testShouldIgnoreOrientationRequestLoop_returnsTrue() {
        doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
        for (int i = 0; i < MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
            assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
                    /* expectedCount */ i);
        }
        assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ true,
                /* expectedCount */ MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP);
    }

    private void assertShouldIgnoreOrientationRequestLoop(boolean shouldIgnore, int expectedCount) {
        if (shouldIgnore) {
            assertTrue(mController.shouldIgnoreOrientationRequestLoop());
        } else {
            assertFalse(mController.shouldIgnoreOrientationRequestLoop());
        }
        assertEquals(expectedCount, mController.getSetOrientationRequestCounter());
    }

    @Test
    @Test
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
    public void testShouldIgnoreRequestedOrientation_flagIsDisabled_returnsFalse() {
    public void testShouldIgnoreRequestedOrientation_flagIsDisabled_returnsFalse() {