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

Commit 59302ac1 authored by Graciela Wissen Putri's avatar Graciela Wissen Putri
Browse files

[2/n] API to ignore activity size restrictions on virtual display

Adds an API for privileged actors with CREATE_VIRTUAL_DEVICE permission
to force app to full-screen on their virtual displays by ignoring fixed
orientation, aspect ratio and resizability of apps.

Large screen-specific app compat overrides will not apply to apps on
eligible virtual displays when this treatment is applied. This treatment
will be contained within the virtual displays of the virtual device.
User fullscreen override applied from Settings > App info > Aspect ratio
(experimental) will also not affect apps within the virtual display.

Developers can opt out of this treatment by setting
PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE to false in their manifest.

Flag: com.android.window.flags.vdm_force_app_universal_resizable_api
Bug: 372848702
Bug: 337894172
Test: atest AppCompatAspectRatioOverridesTest
Change-Id: I893dd477594dac51b3b5882860a8d84df4778950
parent 8d4a96e4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -5271,11 +5271,13 @@ package android.hardware.display {
  public final class VirtualDisplayConfig implements android.os.Parcelable {
    method @FlaggedApi("android.companion.virtualdevice.flags.virtual_display_insets") @Nullable public android.view.DisplayCutout getDisplayCutout();
    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") public boolean isHomeSupported();
    method @FlaggedApi("com.android.window.flags.vdm_force_app_universal_resizable_api") public boolean isIgnoreActivitySizeRestrictions();
  }
  public static final class VirtualDisplayConfig.Builder {
    method @FlaggedApi("android.companion.virtualdevice.flags.virtual_display_insets") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setHomeSupported(boolean);
    method @FlaggedApi("com.android.window.flags.vdm_force_app_universal_resizable_api") @NonNull public android.hardware.display.VirtualDisplayConfig.Builder setIgnoreActivitySizeRestrictions(boolean);
  }
}
+45 −3
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ public final class VirtualDisplayConfig implements Parcelable {
    private final float mRequestedRefreshRate;
    private final boolean mIsHomeSupported;
    private final DisplayCutout mDisplayCutout;
    private final boolean mIgnoreActivitySizeRestrictions;

    private VirtualDisplayConfig(
            @NonNull String name,
@@ -74,7 +75,8 @@ public final class VirtualDisplayConfig implements Parcelable {
            @NonNull ArraySet<String> displayCategories,
            float requestedRefreshRate,
            boolean isHomeSupported,
            @Nullable DisplayCutout displayCutout) {
            @Nullable DisplayCutout displayCutout,
            boolean ignoreActivitySizeRestrictions) {
        mName = name;
        mWidth = width;
        mHeight = height;
@@ -88,6 +90,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        mRequestedRefreshRate = requestedRefreshRate;
        mIsHomeSupported = isHomeSupported;
        mDisplayCutout = displayCutout;
        mIgnoreActivitySizeRestrictions = ignoreActivitySizeRestrictions;
    }

    /**
@@ -192,6 +195,20 @@ public final class VirtualDisplayConfig implements Parcelable {
        return android.companion.virtual.flags.Flags.vdmCustomHome() && mIsHomeSupported;
    }

    /**
     * Whether this virtual display ignores fixed orientation, aspect ratio and resizability
     * of apps.
     *
     * @see Builder#setIgnoreActivitySizeRestrictions(boolean)
     * @hide
     */
    @FlaggedApi(com.android.window.flags.Flags.FLAG_VDM_FORCE_APP_UNIVERSAL_RESIZABLE_API)
    @SystemApi
    public boolean isIgnoreActivitySizeRestrictions() {
        return mIgnoreActivitySizeRestrictions
                && com.android.window.flags.Flags.vdmForceAppUniversalResizableApi();
    }

    /**
     * Returns the display categories.
     *
@@ -227,6 +244,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        dest.writeFloat(mRequestedRefreshRate);
        dest.writeBoolean(mIsHomeSupported);
        DisplayCutout.ParcelableWrapper.writeCutoutToParcel(mDisplayCutout, dest, flags);
        dest.writeBoolean(mIgnoreActivitySizeRestrictions);
    }

    @Override
@@ -253,6 +271,7 @@ public final class VirtualDisplayConfig implements Parcelable {
                && Objects.equals(mDisplayCategories, that.mDisplayCategories)
                && mRequestedRefreshRate == that.mRequestedRefreshRate
                && mIsHomeSupported == that.mIsHomeSupported
                && mIgnoreActivitySizeRestrictions == that.mIgnoreActivitySizeRestrictions
                && Objects.equals(mDisplayCutout, that.mDisplayCutout);
    }

@@ -261,7 +280,8 @@ public final class VirtualDisplayConfig implements Parcelable {
        int hashCode = Objects.hash(
                mName, mWidth, mHeight, mDensityDpi, mFlags, mSurface, mUniqueId,
                mDisplayIdToMirror, mWindowManagerMirroringEnabled, mDisplayCategories,
                mRequestedRefreshRate, mIsHomeSupported, mDisplayCutout);
                mRequestedRefreshRate, mIsHomeSupported, mDisplayCutout,
                mIgnoreActivitySizeRestrictions);
        return hashCode;
    }

@@ -282,6 +302,7 @@ public final class VirtualDisplayConfig implements Parcelable {
                + " mRequestedRefreshRate=" + mRequestedRefreshRate
                + " mIsHomeSupported=" + mIsHomeSupported
                + " mDisplayCutout=" + mDisplayCutout
                + " mIgnoreActivitySizeRestrictions=" + mIgnoreActivitySizeRestrictions
                + ")";
    }

@@ -299,6 +320,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        mRequestedRefreshRate = in.readFloat();
        mIsHomeSupported = in.readBoolean();
        mDisplayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(in);
        mIgnoreActivitySizeRestrictions = in.readBoolean();
    }

    @NonNull
@@ -332,6 +354,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        private float mRequestedRefreshRate = 0.0f;
        private boolean mIsHomeSupported = false;
        private DisplayCutout mDisplayCutout = null;
        private boolean mIgnoreActivitySizeRestrictions = false;

        /**
         * Creates a new Builder.
@@ -505,6 +528,24 @@ public final class VirtualDisplayConfig implements Parcelable {
            return this;
        }

        /**
         * Sets whether this display ignores fixed orientation, aspect ratio and resizability
         * of apps.
         *
         * <p>Note: setting to {@code true} requires the display to have
         * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED}. If this is false, this property
         * is ignored.</p>
         *
         * @hide
         */
        @FlaggedApi(com.android.window.flags.Flags.FLAG_VDM_FORCE_APP_UNIVERSAL_RESIZABLE_API)
        @SystemApi
        @NonNull
        public Builder setIgnoreActivitySizeRestrictions(boolean enabled) {
            mIgnoreActivitySizeRestrictions = enabled;
            return this;
        }

        /**
         * Builds the {@link VirtualDisplayConfig} instance.
         */
@@ -523,7 +564,8 @@ public final class VirtualDisplayConfig implements Parcelable {
                    mDisplayCategories,
                    mRequestedRefreshRate,
                    mIsHomeSupported,
                    mDisplayCutout);
                    mDisplayCutout,
                    mIgnoreActivitySizeRestrictions);
        }
    }
}
+14 −2
Original line number Diff line number Diff line
@@ -1889,6 +1889,7 @@ public final class DisplayManagerService extends SystemService {
            final String displayUniqueId = VirtualDisplayAdapter.generateDisplayUniqueId(
                    packageName, callingUid, virtualDisplayConfig);

            boolean shouldClearDisplayWindowSettings = false;
            if (virtualDisplayConfig.isHomeSupported()) {
                if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) {
                    Slog.w(TAG, "Display created with home support but lacks "
@@ -1900,6 +1901,18 @@ public final class DisplayManagerService extends SystemService {
                } else {
                    mWindowManagerInternal.setHomeSupportedOnDisplay(displayUniqueId,
                            Display.TYPE_VIRTUAL, true);
                    shouldClearDisplayWindowSettings = true;
                }
            }

            if (virtualDisplayConfig.isIgnoreActivitySizeRestrictions()) {
                if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) {
                    Slog.w(TAG, "Display created to ignore activity size restrictions, "
                            + "but lacks VIRTUAL_DISPLAY_FLAG_TRUSTED, ignoring the request.");
                } else {
                    mWindowManagerInternal.setIgnoreActivitySizeRestrictionsOnDisplay(
                            displayUniqueId, Display.TYPE_VIRTUAL, true);
                    shouldClearDisplayWindowSettings = true;
                }
            }

@@ -1922,8 +1935,7 @@ public final class DisplayManagerService extends SystemService {
                }
            }

            if (displayId == Display.INVALID_DISPLAY && virtualDisplayConfig.isHomeSupported()
                    && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
            if (displayId == Display.INVALID_DISPLAY && shouldClearDisplayWindowSettings) {
                // Failed to create the virtual display, so we should clean up the WM settings
                // because it won't receive the onDisplayRemoved callback.
                mWindowManagerInternal.clearDisplaySettings(displayUniqueId, Display.TYPE_VIRTUAL);
+11 −1
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_POSITION_MULTIPLIER_CENTER;
import static com.android.server.wm.AppCompatConfiguration.MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO;
import static com.android.server.wm.AppCompatUtils.isChangeEnabled;
import static com.android.server.wm.AppCompatUtils.isDisplayIgnoreActivitySizeRestrictions;

import android.annotation.NonNull;
import android.content.pm.IPackageManager;
@@ -175,8 +176,17 @@ class AppCompatAspectRatioOverrides {
                && mActivityRecord.mDisplayContent.getIgnoreOrientationRequest();
    }

    /**
     * Whether to ignore fixed orientation, aspect ratio and resizability of activity.
     */
    boolean hasFullscreenOverride() {
        return shouldApplyUserFullscreenOverride() || isSystemOverrideToFullscreenEnabled();
        return shouldApplyUserFullscreenOverride() || isSystemOverrideToFullscreenEnabled()
                || shouldIgnoreActivitySizeRestrictionsForDisplay();
    }

    boolean shouldIgnoreActivitySizeRestrictionsForDisplay() {
        return isDisplayIgnoreActivitySizeRestrictions(mActivityRecord)
                && !mAllowOrientationOverrideOptProp.isFalse();
    }

    float getUserMinAspectRatio() {
+9 −4
Original line number Diff line number Diff line
@@ -53,11 +53,16 @@ class AppCompatOrientationPolicy {

    @ActivityInfo.ScreenOrientation
    int overrideOrientationIfNeeded(@ActivityInfo.ScreenOrientation int candidate) {
        final AppCompatAspectRatioOverrides aspectRatioOverrides =
                mAppCompatOverrides.getAppCompatAspectRatioOverrides();
        // Ignore all orientation requests of activities for eligible virtual displays.
        if (aspectRatioOverrides.shouldIgnoreActivitySizeRestrictionsForDisplay()) {
            return SCREEN_ORIENTATION_USER;
        }
        final DisplayContent displayContent = mActivityRecord.mDisplayContent;
        final boolean isIgnoreOrientationRequestEnabled = displayContent != null
                && displayContent.getIgnoreOrientationRequest();
        final boolean hasFullscreenOverride = mAppCompatOverrides
                .getAppCompatAspectRatioOverrides().hasFullscreenOverride();
        final boolean hasFullscreenOverride = aspectRatioOverrides.hasFullscreenOverride();
        final boolean shouldCameraCompatControlOrientation =
                AppCompatCameraPolicy.shouldCameraCompatControlOrientation(mActivityRecord);
        if (hasFullscreenOverride && isIgnoreOrientationRequestEnabled
@@ -76,8 +81,8 @@ class AppCompatOrientationPolicy {
        // In some cases (e.g. Kids app) we need to map the candidate orientation to some other
        // orientation.
        candidate = mActivityRecord.mWmService.mapOrientationRequest(candidate);
        final boolean shouldApplyUserMinAspectRatioOverride = mAppCompatOverrides
                .getAppCompatAspectRatioOverrides().shouldApplyUserMinAspectRatioOverride();
        final boolean shouldApplyUserMinAspectRatioOverride = aspectRatioOverrides
                .shouldApplyUserMinAspectRatioOverride();
        if (shouldApplyUserMinAspectRatioOverride && (!isFixedOrientation(candidate)
                || candidate == SCREEN_ORIENTATION_LOCKED)) {
            Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate)
Loading