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

Commit 4a11fde2 authored by jainrachit's avatar jainrachit
Browse files

[7/n] Add application and activity property to allow safe region letterboxing

- This new property can be used by activities or applications to allow safe region letterboxing.
- Once set, the platform will not override this behavior.
- Not setting this property at all, or setting this property to true has no effect.
- Setting this property to false will not allow the platform to
  letterbox the activity or application within a safe region.

Bug: 380132497
Bug: 368408934
Flag: com.android.window.flags.safe_region_letterboxing
Test: atest SizeCompatTests
Change-Id: I5835ee3a7b55ffdaeb696c3ee9ae70d658632947
parent c6aa5189
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -1513,6 +1513,44 @@ public interface WindowManager extends ViewManager {
    String PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY =
            "android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY";

    /**
     * Application or Activity level
     * {@link android.content.pm.PackageManager.Property PackageManager.Property} that specifies
     * whether this package or activity wants to allow safe region letterboxing. A safe
     * region policy may be applied by the system to improve the user experience by ensuring that
     * the activity does not have any content that is occluded and has the correct current
     * window metrics.
     *
     * <p>Not setting the property at all defaults it to {@code true}. In such a case, the activity
     * will be letterboxed in the safe region.
     *
     * <p>To not allow the safe region letterboxing, add this property to your app
     * manifest and set the value to {@code false}. An app should ignore safe region
     * letterboxing if it can handle bounds and insets from all four directions correctly when a
     * request to go immersive is denied by the system. If the application does not allow safe
     * region letterboxing, the system will not override this behavior.
     *
     * <p><b>Syntax:</b>
     * <pre>
     * &lt;application&gt;
     *   &lt;property
     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_SAFE_REGION_LETTERBOXING"
     *     android:value="false"/&gt;
     * &lt;/application&gt;
     * </pre>or
     * <pre>
     * &lt;activity&gt;
     *   &lt;property
     *     android:name="android.window.PROPERTY_COMPAT_ALLOW_SAFE_REGION_LETTERBOXING"
     *     android:value="false"/&gt;
     * &lt;/activity&gt;
     * </pre>
     * @hide
     */
    @FlaggedApi(Flags.FLAG_SAFE_REGION_LETTERBOXING)
    String PROPERTY_COMPAT_ALLOW_SAFE_REGION_LETTERBOXING =
            "android.window.PROPERTY_COMPAT_ALLOW_SAFE_REGION_LETTERBOXING";

    /**
     * @hide
     */
+1 −1
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ class AppCompatController {
        mOrientationPolicy = new AppCompatOrientationPolicy(activityRecord, mAppCompatOverrides);
        mAspectRatioPolicy = new AppCompatAspectRatioPolicy(activityRecord,
                mTransparentPolicy, mAppCompatOverrides);
        mSafeRegionPolicy = new AppCompatSafeRegionPolicy(activityRecord);
        mSafeRegionPolicy = new AppCompatSafeRegionPolicy(activityRecord, packageManager);
        mReachabilityPolicy = new AppCompatReachabilityPolicy(activityRecord,
                wmService.mAppCompatConfiguration);
        mLetterboxPolicy = new AppCompatLetterboxPolicy(activityRecord,
+63 −7
Original line number Diff line number Diff line
@@ -16,11 +16,15 @@

package com.android.server.wm;

import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_SAFE_REGION_LETTERBOXING;

import android.annotation.NonNull;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Rect;

import java.io.PrintWriter;
import java.util.function.BooleanSupplier;

/**
 * Encapsulate app compat policy logic related to a safe region.
@@ -28,25 +32,66 @@ import java.io.PrintWriter;
class AppCompatSafeRegionPolicy {
    @NonNull
    private final ActivityRecord mActivityRecord;
    @NonNull
    final PackageManager mPackageManager;
    // Whether the Activity needs to be in the safe region bounds.
    private boolean mNeedsSafeRegionBounds = false;
    // Denotes the latest safe region bounds. Can be empty if the activity or the ancestors do
    // not have any safe region bounds.
    @NonNull
    private final Rect mLatestSafeRegionBounds = new Rect();
    // Whether the activity has allowed safe region letterboxing. This can be set through the
    // manifest and the default value is true.
    @NonNull
    private final BooleanSupplier mAllowSafeRegionLetterboxing;

    AppCompatSafeRegionPolicy(@NonNull ActivityRecord activityRecord) {
    AppCompatSafeRegionPolicy(@NonNull ActivityRecord activityRecord,
            @NonNull PackageManager packageManager) {
        mActivityRecord = activityRecord;
        mPackageManager = packageManager;
        mAllowSafeRegionLetterboxing = AppCompatUtils.asLazy(() -> {
            // Application level property.
            if (allowSafeRegionLetterboxing(packageManager)) {
                return true;
            }
            // Activity level property.
            try {
                return packageManager.getPropertyAsUser(
                        PROPERTY_COMPAT_ALLOW_SAFE_REGION_LETTERBOXING,
                        mActivityRecord.mActivityComponent.getPackageName(),
                        mActivityRecord.mActivityComponent.getClassName(),
                        mActivityRecord.mUserId).getBoolean();
            } catch (PackageManager.NameNotFoundException e) {
                return true;
            }
        });
    }

    private boolean allowSafeRegionLetterboxing(PackageManager pm) {
        try {
            return pm.getPropertyAsUser(
                    PROPERTY_COMPAT_ALLOW_SAFE_REGION_LETTERBOXING,
                    mActivityRecord.packageName,
                    /* className */ null,
                    mActivityRecord.mUserId).getBoolean();
        } catch (PackageManager.NameNotFoundException e) {
            return true;
        }
    }

    /**
     * Computes the latest safe region bounds in
     * {@link ActivityRecord#resolveOverrideConfiguration(Configuration)} since the activity has not
     * been attached to the parent container when the ActivityRecord is instantiated.
     * been attached to the parent container when the ActivityRecord is instantiated. Note that the
     * latest safe region bounds will be empty if activity has not allowed safe region letterboxing.
     *
     * @return latest safe region bounds as set on an ancestor window container.
     */
    public Rect getLatestSafeRegionBounds() {
        if (!allowSafeRegionLetterboxing()) {
            mLatestSafeRegionBounds.setEmpty();
            return null;
        }
        // Get the latest safe region bounds since the bounds could have changed
        final Rect latestSafeRegionBounds = mActivityRecord.getSafeRegionBounds();
        if (latestSafeRegionBounds != null) {
@@ -67,7 +112,7 @@ class AppCompatSafeRegionPolicy {
        }
        // If activity can not be letterboxed for a safe region only or it has not been attached
        // to a WindowContainer yet.
        if (!isLetterboxedForSafeRegionOnly() || mActivityRecord.getParent() == null) {
        if (!isLetterboxedForSafeRegionOnlyAllowed() || mActivityRecord.getParent() == null) {
            return;
        }
        resolvedConfig.windowConfiguration.setBounds(mLatestSafeRegionBounds);
@@ -80,10 +125,11 @@ class AppCompatSafeRegionPolicy {
     * independently when no other letterboxing condition is triggered. This method helps detecting
     * the latter case.
     *
     * @return {@code true} if the activity is letterboxed only due to the safe region being set on
     * the current or ancestor window container.
     * @return {@code true} if this application or activity has allowed safe region letterboxing and
     * can be letterboxed only due to the safe region being set on the current or ancestor window
     * container.
     */
    boolean isLetterboxedForSafeRegionOnly() {
    boolean isLetterboxedForSafeRegionOnlyAllowed() {
        return !mActivityRecord.areBoundsLetterboxed() && getNeedsSafeRegionBounds()
                && getLatestSafeRegionBounds() != null;
    }
@@ -102,10 +148,20 @@ class AppCompatSafeRegionPolicy {
        return mNeedsSafeRegionBounds;
    }

    /** @see android.view.WindowManager#PROPERTY_COMPAT_ALLOW_SAFE_REGION_LETTERBOXING */
    boolean allowSafeRegionLetterboxing() {
        return mAllowSafeRegionLetterboxing.getAsBoolean();
    }

    void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
        if (mNeedsSafeRegionBounds) {
            pw.println(prefix + " mNeedsSafeRegionBounds=true");
        }
        pw.println(prefix + " isLetterboxedForSafeRegionOnly=" + isLetterboxedForSafeRegionOnly());
        if (isLetterboxedForSafeRegionOnlyAllowed()) {
            pw.println(prefix + " isLetterboxForSafeRegionOnlyAllowed=true");
        }
        if (!allowSafeRegionLetterboxing()) {
            pw.println(prefix + " allowSafeRegionLetterboxing=false");
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -243,7 +243,7 @@ final class AppCompatUtils {
            return "ASPECT_RATIO";
        }
        if (activityRecord.mAppCompatController.getSafeRegionPolicy()
                .isLetterboxedForSafeRegionOnly()) {
                .isLetterboxedForSafeRegionOnlyAllowed()) {
            return "SAFE_REGION";
        }
        return "UNKNOWN_REASON";
+1 −1
Original line number Diff line number Diff line
@@ -3869,7 +3869,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        return mActivityRecord != null && !isStartingWindowAssociatedToTask()
                && (mActivityRecord.areBoundsLetterboxed() || isLetterboxedForDisplayCutout()
                || mActivityRecord.mAppCompatController
                .getSafeRegionPolicy().isLetterboxedForSafeRegionOnly());
                .getSafeRegionPolicy().isLetterboxedForSafeRegionOnlyAllowed());
    }

    /** Returns {@code true} if the window is letterboxed for the display cutout. */
Loading