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

Commit 1f8e2b3f authored by Kazuki Takise's avatar Kazuki Takise Committed by Android (Google) Code Review
Browse files

Merge "Upscale SCM for display and windowing mode changes" into main

parents 83d9cf07 faafea6e
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -53,6 +53,9 @@ class AppCompatDisplayCompatModePolicy {
    @NonNull
    private final ActivityRecord mActivityRecord;

    /**
     * {@code true} if the activity has moved to a different display and has not been restarted yet.
     */
    private boolean mDisplayChangedWithoutRestart;

    AppCompatDisplayCompatModePolicy(@NonNull ActivityRecord activityRecord) {
@@ -107,6 +110,14 @@ class AppCompatDisplayCompatModePolicy {
        }
    }

    /**
     * Returns {@code true} if the activity has moved to a different display and has not been
     * restarted yet.
     */
    boolean getDisplayChangedWithoutRestart() {
        return mDisplayChangedWithoutRestart;
    }

    /**
     * Called when the activity's process is restarted.
     */
+8 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;

import static com.android.server.wm.AppCompatUtils.computeAspectRatio;
import static com.android.server.wm.AppCompatUtils.isInDesktopMode;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -64,6 +65,11 @@ class AppCompatDisplayInsets {
     * {@link Configuration#screenHeightDp}.
     */
    final Rect[] mStableInsets = new Rect[4];
    /**
     * Whether the activity was originally launched in desktop mode or not. Used for the heuristic
     * to determine whether the app should be upscaled or not.
     */
    final boolean mInDesktopMode;

    /** Constructs the environment to simulate the bounds behavior of the given container. */
    AppCompatDisplayInsets(@NonNull DisplayContent display, @NonNull ActivityRecord container,
@@ -71,6 +77,8 @@ class AppCompatDisplayInsets {
        mOriginalRotation = display.getRotation();
        mIsFloating = container.getWindowConfiguration().tasksAreFloating();
        mOriginalRequestedOrientation = container.getRequestedConfigurationOrientation();
        mInDesktopMode = isInDesktopMode(container.mAtmService.mContext,
                container.getWindowConfiguration().getWindowingMode());
        if (mIsFloating) {
            final Rect containerBounds = container.getWindowConfiguration().getBounds();
            mWidth = containerBounds.width();
+38 −4
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.internal.perfetto.protos.Windowmanagerservice.ActivityRecordProto.IN_SIZE_COMPAT_MODE;
import static android.window.DesktopExperienceFlags.ENABLE_SIZE_COMPAT_MODE_IMPROVEMENTS_FOR_CONNECTED_DISPLAYS;
import static android.window.DesktopExperienceFlags.ENABLE_UPSCALING_SIZE_COMPAT_ON_EXITING_DESKTOP_BUGFIX;

import static com.android.server.wm.AppCompatUtils.isInDesktopMode;

@@ -33,6 +34,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
import android.view.Display;

import java.io.PrintWriter;
import java.util.function.DoubleSupplier;
@@ -572,12 +574,44 @@ class AppCompatSizeCompatModePolicy {
        final int contentH = resolvedAppBounds.height();
        final int viewportW = containerAppBounds.width();
        final int viewportH = containerAppBounds.height();
        // Allow an application to be up-scaled if its window is smaller than its
        // original container or if it's a freeform window in desktop mode.
        boolean shouldAllowUpscaling = !(contentW <= viewportW && contentH <= viewportH)
                || isInDesktopMode(mActivityRecord.mAtmService.mContext,
        final boolean isInDesktopMode = isInDesktopMode(mActivityRecord.mAtmService.mContext,
                newParentConfig.windowConfiguration.getWindowingMode());
        // Allow an application to be up-scaled if its window is smaller than its
        // original container, if it's a freeform window in desktop mode, or if display or windowing
        // mode has changed in some special conditions.
        final boolean shouldAllowUpscaling = !(contentW <= viewportW && contentH <= viewportH)
                || isInDesktopMode
                || shouldAllowUpscalingForDisplayOrWindowingModeChange(isInDesktopMode);
        return shouldAllowUpscaling ? Math.min(
                (float) viewportW / contentW, (float) viewportH / contentH) : 1f;
    }

    /**
     * Returns whether the activity should be upscaled due to a change in display or windowing
     * mode. Upscaling is generally disabled in fullscreen to avoid pixelation etc. However, it is
     * enabled in specific scenarios to prevent the app from becoming too small in a parent window,
     * such as when:
     * - Moving from an external display to a smaller phone screen.
     * - Transitioning from desktop mode to fullscreen.
     * This treatment is not applied to internal displays that ignore orientation requests to
     * maintain consistent scaling behavior with orientation changes on those displays.
     */
    private boolean shouldAllowUpscalingForDisplayOrWindowingModeChange(boolean isInDesktopMode) {
        final boolean launchedInAndExitedFromDesktop  = getAppCompatDisplayInsets() != null
                && getAppCompatDisplayInsets().mInDesktopMode && !isInDesktopMode;
        final boolean hasMovedBetweenDisplays = mActivityRecord.mAppCompatController
                .getDisplayCompatModePolicy().getDisplayChangedWithoutRestart();
        final boolean isOnIgnoreOrientationRequestInternalDisplay = isOnInternalDisplay()
                && mActivityRecord.getDisplayContent().getIgnoreOrientationRequest();

        // TODO(b/432329483): Polish the policy for desktop-first devices.
        return ENABLE_UPSCALING_SIZE_COMPAT_ON_EXITING_DESKTOP_BUGFIX.isTrue()
                && (launchedInAndExitedFromDesktop || hasMovedBetweenDisplays)
                && !isOnIgnoreOrientationRequestInternalDisplay;
    }

    /** Returns whether the activity is on an internal display. */
    private boolean isOnInternalDisplay() {
        return mActivityRecord.getDisplayContent().getDisplay().getType() == Display.TYPE_INTERNAL;
    }
}
+58 −2
Original line number Diff line number Diff line
@@ -34,6 +34,9 @@ import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_SPLIT_SCRE
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.TYPE_EXTERNAL;
import static android.view.Display.TYPE_INTERNAL;
import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
@@ -67,7 +70,6 @@ import static com.android.server.wm.ActivityRecord.State.STOPPED;
import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_POSITION_MULTIPLIER_CENTER;
import static com.android.server.wm.AppCompatUtils.computeAspectRatio;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.window.flags.Flags.FLAG_ENABLE_SIZE_COMPAT_MODE_IMPROVEMENTS_FOR_CONNECTED_DISPLAYS;

import static com.google.common.truth.Truth.assertThat;

@@ -564,7 +566,7 @@ public class SizeCompatTests extends WindowTestsBase {
        assertDownScaled();
    }

    @EnableFlags(FLAG_ENABLE_SIZE_COMPAT_MODE_IMPROVEMENTS_FOR_CONNECTED_DISPLAYS)
    @EnableFlags(Flags.FLAG_ENABLE_SIZE_COMPAT_MODE_IMPROVEMENTS_FOR_CONNECTED_DISPLAYS)
    @Test
    public void testFixedMiscConfigurationWhenMovingToDisplay() {
        setUpDisplaySizeWithApp(1000, 2500);
@@ -4594,6 +4596,60 @@ public class SizeCompatTests extends WindowTestsBase {
        assertEquals(notchHeight, appBounds.top - bounds.top);
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_UPSCALING_SIZE_COMPAT_ON_EXITING_DESKTOP_BUGFIX)
    public void testUpscaling_boundsUpscaledWithWindowingModeChange() {
        allowDesktopMode();

        // Launch an SCM app in freeform on an external display.
        final int dw = 2000;
        final int dh = 1600;
        final DisplayInfo displayInfo = new DisplayInfo();
        displayInfo.copyFrom(mDisplayInfo);
        displayInfo.type = TYPE_EXTERNAL;
        displayInfo.displayId = DEFAULT_DISPLAY + 1;
        displayInfo.logicalWidth = dw;
        displayInfo.logicalHeight = dh;
        final DisplayContent display = new TestDisplayContent.Builder(mAtm, displayInfo).build();
        display.getDefaultTaskDisplayArea()
                .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
        final TaskBuilder taskBuilder =
                new TaskBuilder(mSupervisor).setWindowingMode(WINDOWING_MODE_FREEFORM);
        setUpApp(display, null /* appBuilder */, taskBuilder);
        Rect bounds = new Rect(0, 0, 600, 800);
        mTask.setBounds(bounds);
        mTask.onConfigurationChanged(mTask.getDisplayArea().getConfiguration());
        prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
        assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM, mTask.getWindowingMode());
        assertFitted();

        // Exit freeform into fullscreen.
        display.getDefaultTaskDisplayArea()
                .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
        mTask.setBounds(null);
        mActivity.onConfigurationChanged(mTask.getConfiguration());
        assertUpScaled();

        // Move to a fullscreen, ignore-orientation-request, internal display.
        final DisplayInfo internalDisplayInfo = new DisplayInfo();
        internalDisplayInfo.copyFrom(display.getDisplayInfo());
        internalDisplayInfo.type = TYPE_INTERNAL;
        internalDisplayInfo.displayId = display.getDisplayInfo().displayId + 1;
        final DisplayContent internalDisplay =
                new TestDisplayContent.Builder(mAtm, internalDisplayInfo).build();
        mTask.mWmService.mRoot.moveRootTaskToDisplay(mTask.mTaskId, internalDisplay.mDisplayId,
                true /* onTop */);
        internalDisplay.setIgnoreOrientationRequest(true);
        mActivity.onConfigurationChanged(mTask.getConfiguration());
        assertTrue(mActivity.inSizeCompatMode());
        assertEquals(1f, mActivity.getCompatScale(), 1e7);

        // Make the display not ignore-orientation-request.
        internalDisplay.setIgnoreOrientationRequest(false);
        mActivity.onConfigurationChanged(mTask.getConfiguration());
        assertUpScaled();
    }


    @Test
    @EnableFlags(Flags.FLAG_IGNORE_ASPECT_RATIO_RESTRICTIONS_FOR_RESIZEABLE_FREEFORM_ACTIVITIES)