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

Commit 65ffa6db authored by Massimo Carli's avatar Massimo Carli
Browse files

Force Kids app to use LANDSCAPE when in REVERSE_LANDSCAPE

A few apps in Kids Space request "reverseLandscape" orientation when
Display#getRotation returns ROTATION_270 expecting it to correspond
to the seascape display orientation while it may correspond to the
landscape one when config_reverseDefaultRotation is set to true.

This CL overrides the "reverseLandscape" orientation with "landscape"
in the context of apps running in the Kids space when
config_reverseDefaultRotation is set to true

Fixes: 265589619
Test: Run `atest WmTests:WindowManagerServiceTests`
      Run `atest WMShellUnitTests:KidsModeTaskOrganizerTest`
      Run `atest WmTests:LetterboxUiControllerTest`

Change-Id: I85688413571478f5acaa340624bb470f5aeb422f
parent 05557900
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -73,11 +73,17 @@ interface ITaskOrganizerController {

    /**
     * Controls whether ignore orientation request logic in {@link
     * com.android.server.wm.DisplayArea} is disabled at runtime.
     * com.android.server.wm.DisplayArea} is disabled at runtime and how to optionally map some
     * requested orientations to others.
     *
     * @param isDisabled when {@code true}, the system always ignores the value of {@link
     *                   com.android.server.wm.DisplayArea#getIgnoreOrientationRequest} and app
     *                   requested orientation is respected.
     * @param fromOrientations The orientations we want to map to the correspondent orientations
     *                        in toOrientation.
     * @param toOrientations The orientations we map to the ones in fromOrientations at the same
     *                       index
     */
     void setIsIgnoreOrientationRequestDisabled(boolean isDisabled);
     void setOrientationRequestPolicy(boolean isIgnoreOrientationRequestDisabled,
            in int[] fromOrientations, in int[] toOrientations);
}
+13 −6
Original line number Diff line number Diff line
@@ -270,17 +270,24 @@ public class TaskOrganizer extends WindowOrganizer {

    /**
     * Controls whether ignore orientation request logic in {@link
     * com.android.server.wm.DisplayArea} is disabled at runtime.
     * com.android.server.wm.DisplayArea} is disabled at runtime and how to optionally map some
     * requested orientation to others.
     *
     * @param isDisabled when {@code true}, the system always ignores the value of {@link
     *                   com.android.server.wm.DisplayArea#getIgnoreOrientationRequest} and app
     *                   requested orientation is respected.
     * @param isIgnoreOrientationRequestDisabled when {@code true}, the system always ignores the
     *           value of  {@link com.android.server.wm.DisplayArea#getIgnoreOrientationRequest}
     *           and app requested orientation is respected.
     * @param fromOrientations The orientations we want to map to the correspondent orientations
     *                        in toOrientation.
     * @param toOrientations The orientations we map to the ones in fromOrientations at the same
     *                       index
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
    public void setIsIgnoreOrientationRequestDisabled(boolean isDisabled) {
    public void setOrientationRequestPolicy(boolean isIgnoreOrientationRequestDisabled,
            @Nullable int[] fromOrientations, @Nullable int[] toOrientations) {
        try {
            mTaskOrganizerController.setIsIgnoreOrientationRequestDisabled(isDisabled);
            mTaskOrganizerController.setOrientationRequestPolicy(isIgnoreOrientationRequestDisabled,
                    fromOrientations, toOrientations);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+24 −2
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
import static android.view.Display.DEFAULT_DISPLAY;

import android.app.ActivityManager;
@@ -33,6 +35,7 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.view.Display;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.SurfaceControl;
@@ -43,6 +46,7 @@ import android.window.WindowContainerTransaction;

import androidx.annotation.NonNull;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
@@ -80,6 +84,12 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
    private final DisplayController mDisplayController;
    private final DisplayInsetsController mDisplayInsetsController;

    /**
     * The value of the {@link R.bool.config_reverseDefaultRotation} property which defines how
     * {@link Display#getRotation} values are mapped to screen orientations
     */
    private final boolean mReverseDefaultRotationEnabled;

    @VisibleForTesting
    ActivityManager.RunningTaskInfo mLaunchRootTask;
    @VisibleForTesting
@@ -168,6 +178,8 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
        mDisplayInsetsController = displayInsetsController;
        mKidsModeSettingsObserver = kidsModeSettingsObserver;
        shellInit.addInitCallback(this::onInit, this);
        mReverseDefaultRotationEnabled = context.getResources().getBoolean(
                R.bool.config_reverseDefaultRotation);
    }

    public KidsModeTaskOrganizer(
@@ -191,6 +203,8 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
        mDisplayController = displayController;
        mDisplayInsetsController = displayInsetsController;
        shellInit.addInitCallback(this::onInit, this);
        mReverseDefaultRotationEnabled = context.getResources().getBoolean(
                R.bool.config_reverseDefaultRotation);
    }

    /**
@@ -269,7 +283,14 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
        // Needed since many Kids apps aren't optimised to support both orientations and it will be
        // hard for kids to understand the app compat mode.
        // TODO(229961548): Remove ignoreOrientationRequest exception for Kids Mode once possible.
        setIsIgnoreOrientationRequestDisabled(true);
        if (mReverseDefaultRotationEnabled) {
            setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
                    /* fromOrientations */ new int[]{SCREEN_ORIENTATION_REVERSE_LANDSCAPE},
                    /* toOrientations */ new int[]{SCREEN_ORIENTATION_LANDSCAPE});
        } else {
            setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ true,
                    /* fromOrientations */ null, /* toOrientations */ null);
        }
        final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
        if (displayLayout != null) {
            mDisplayWidth = displayLayout.width();
@@ -290,7 +311,8 @@ public class KidsModeTaskOrganizer extends ShellTaskOrganizer {

    @VisibleForTesting
    void disable() {
        setIsIgnoreOrientationRequestDisabled(false);
        setOrientationRequestPolicy(/* isIgnoreOrientationRequestDisabled */ false,
                /* fromOrientations */ null, /* toOrientations */ null);
        mDisplayInsetsController.removeInsetsChangedListener(DEFAULT_DISPLAY,
                mOnInsetsChangedListener);
        mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
+12 −5
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -77,6 +78,7 @@ public class KidsModeTaskOrganizerTest extends ShellTestCase {
    @Mock private ShellInit mShellInit;
    @Mock private ShellCommandHandler mShellCommandHandler;
    @Mock private DisplayInsetsController mDisplayInsetsController;
    @Mock private Resources mResources;

    KidsModeTaskOrganizer mOrganizer;

@@ -89,10 +91,12 @@ public class KidsModeTaskOrganizerTest extends ShellTestCase {
        } catch (RemoteException e) {
        }
        // NOTE: KidsModeTaskOrganizer should have a null CompatUIController.
        mOrganizer = spy(new KidsModeTaskOrganizer(mContext, mShellInit, mShellCommandHandler,
                mTaskOrganizerController, mSyncTransactionQueue, mDisplayController,
                mDisplayInsetsController, Optional.empty(), Optional.empty(), mObserver,
                mTestExecutor, mHandler));
        doReturn(mResources).when(mContext).getResources();
        final KidsModeTaskOrganizer kidsModeTaskOrganizer = new KidsModeTaskOrganizer(mContext,
                mShellInit, mShellCommandHandler, mTaskOrganizerController, mSyncTransactionQueue,
                mDisplayController, mDisplayInsetsController, Optional.empty(), Optional.empty(),
                mObserver, mTestExecutor, mHandler);
        mOrganizer = spy(kidsModeTaskOrganizer);
        doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction();
        doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY);
    }
@@ -112,6 +116,8 @@ public class KidsModeTaskOrganizerTest extends ShellTestCase {
        verify(mOrganizer, times(1)).registerOrganizer();
        verify(mOrganizer, times(1)).createRootTask(
                eq(DEFAULT_DISPLAY), eq(WINDOWING_MODE_FULLSCREEN), eq(mOrganizer.mCookie));
        verify(mOrganizer, times(1))
                .setOrientationRequestPolicy(eq(true), any(), any());

        final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
                WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
@@ -132,10 +138,11 @@ public class KidsModeTaskOrganizerTest extends ShellTestCase {
        doReturn(false).when(mObserver).isEnabled();
        mOrganizer.updateKidsModeState();


        verify(mOrganizer, times(1)).disable();
        verify(mOrganizer, times(1)).unregisterOrganizer();
        verify(mOrganizer, times(1)).deleteRootTask(rootTask.token);
        verify(mOrganizer, times(1))
                .setOrientationRequestPolicy(eq(false), any(), any());
        assertThat(mOrganizer.mLaunchRootLeash).isNull();
        assertThat(mOrganizer.mLaunchRootTask).isNull();
    }
+4 −0
Original line number Diff line number Diff line
@@ -455,6 +455,10 @@ final class LetterboxUiController {

    @ScreenOrientation
    int overrideOrientationIfNeeded(@ScreenOrientation int candidate) {
        // In some cases (e.g. Kids app) we need to map the candidate orientation to some other
        // orientation.
        candidate = mActivityRecord.mWmService.mapOrientationRequest(candidate);

        if (FALSE.equals(mBooleanPropertyAllowOrientationOverride)) {
            return candidate;
        }
Loading