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

Commit 4e937c05 authored by Adrian Roos's avatar Adrian Roos Committed by Android (Google) Code Review
Browse files

Merge "Display Cutout: Make API public"

parents 13eec469 d07bafda
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -44718,6 +44718,14 @@ package android.view {
    field public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR;
  }
  public final class DisplayCutout {
    method public android.graphics.Region getBounds();
    method public int getSafeInsetBottom();
    method public int getSafeInsetLeft();
    method public int getSafeInsetRight();
    method public int getSafeInsetTop();
  }
  public final class DragAndDropPermissions implements android.os.Parcelable {
    method public int describeContents();
    method public void release();
@@ -47671,8 +47679,10 @@ package android.view {
  public final class WindowInsets {
    ctor public WindowInsets(android.view.WindowInsets);
    method public android.view.WindowInsets consumeDisplayCutout();
    method public android.view.WindowInsets consumeStableInsets();
    method public android.view.WindowInsets consumeSystemWindowInsets();
    method public android.view.DisplayCutout getDisplayCutout();
    method public int getStableInsetBottom();
    method public int getStableInsetLeft();
    method public int getStableInsetRight();
@@ -47732,6 +47742,7 @@ package android.view {
    field public static final int FIRST_APPLICATION_WINDOW = 1; // 0x1
    field public static final int FIRST_SUB_WINDOW = 1000; // 0x3e8
    field public static final int FIRST_SYSTEM_WINDOW = 2000; // 0x7d0
    field public static final long FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA = 1L; // 0x1L
    field public static final int FLAGS_CHANGED = 4; // 0x4
    field public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 1; // 0x1
    field public static final int FLAG_ALT_FOCUSABLE_IM = 131072; // 0x20000
@@ -47826,6 +47837,7 @@ package android.view {
    field public float buttonBrightness;
    field public float dimAmount;
    field public int flags;
    field public long flags2;
    field public int format;
    field public int gravity;
    field public float horizontalMargin;
+63 −82
Original line number Diff line number Diff line
@@ -21,40 +21,37 @@ import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;

import android.annotation.NonNull;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Parcel;
import android.os.Parcelable;

import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.List;

/**
 * Represents a part of the display that is not functional for displaying content.
 *
 * <p>{@code DisplayCutout} is immutable.
 *
 * @hide will become API
 */
public final class DisplayCutout {

    private static final Rect ZERO_RECT = new Rect(0, 0, 0, 0);
    private static final ArrayList<Point> EMPTY_LIST = new ArrayList<>();
    private static final Rect ZERO_RECT = new Rect();
    private static final Region EMPTY_REGION = new Region();

    /**
     * An instance where {@link #hasCutout()} returns {@code false}.
     * An instance where {@link #isEmpty()} returns {@code true}.
     *
     * @hide
     */
    public static final DisplayCutout NO_CUTOUT =
            new DisplayCutout(ZERO_RECT, ZERO_RECT, EMPTY_LIST);
    public static final DisplayCutout NO_CUTOUT = new DisplayCutout(ZERO_RECT, EMPTY_REGION);

    private final Rect mSafeInsets;
    private final Rect mBoundingRect;
    private final List<Point> mBoundingPolygon;
    private final Region mBounds;

    /**
     * Creates a DisplayCutout instance.
@@ -64,22 +61,18 @@ public final class DisplayCutout {
     * @hide
     */
    @VisibleForTesting
    public DisplayCutout(Rect safeInsets, Rect boundingRect, List<Point> boundingPolygon) {
    public DisplayCutout(Rect safeInsets, Region bounds) {
        mSafeInsets = safeInsets != null ? safeInsets : ZERO_RECT;
        mBoundingRect = boundingRect != null ? boundingRect : ZERO_RECT;
        mBoundingPolygon = boundingPolygon != null ? boundingPolygon : EMPTY_LIST;
        mBounds = bounds != null ? bounds : Region.obtain();
    }

    /**
     * Returns whether there is a cutout.
     *
     * If false, the safe insets will all return zero, and the bounding box or polygon will be
     * empty or outside the content view.
     * Returns true if there is no cutout or it is outside of the content view.
     *
     * @return {@code true} if there is a cutout, {@code false} otherwise
     * @hide
     */
    public boolean hasCutout() {
        return !mSafeInsets.equals(ZERO_RECT);
    public boolean isEmpty() {
        return mSafeInsets.equals(ZERO_RECT);
    }

    /** Returns the inset from the top which avoids the display cutout. */
@@ -103,44 +96,41 @@ public final class DisplayCutout {
    }

    /**
     * Obtains the safe insets in a rect.
     * Returns the safe insets in a rect.
     *
     * @param out a rect which is set to the safe insets.
     * @return a rect which is set to the safe insets.
     * @hide
     */
    public void getSafeInsets(@NonNull Rect out) {
        out.set(mSafeInsets);
    public Rect getSafeInsets() {
        return new Rect(mSafeInsets);
    }

    /**
     * Obtains the bounding rect of the cutout.
     * Returns the bounding region of the cutout.
     *
     * @param outRect is filled with the bounding rect of the cutout. Coordinates are relative
     * @return the bounding region of the cutout. Coordinates are relative
     *         to the top-left corner of the content view.
     */
    public void getBoundingRect(@NonNull Rect outRect) {
        outRect.set(mBoundingRect);
    public Region getBounds() {
        return Region.obtain(mBounds);
    }

    /**
     * Obtains the bounding polygon of the cutout.
     * Returns the bounding rect of the cutout.
     *
     * @param outPolygon is filled with a list of points representing the corners of a convex
     *         polygon which covers the cutout. Coordinates are relative to the
     *         top-left corner of the content view.
     * @return the bounding rect of the cutout. Coordinates are relative
     *         to the top-left corner of the content view.
     * @hide
     */
    public void getBoundingPolygon(List<Point> outPolygon) {
        outPolygon.clear();
        for (int i = 0; i < mBoundingPolygon.size(); i++) {
            outPolygon.add(new Point(mBoundingPolygon.get(i)));
        }
    public Rect getBoundingRect() {
        // TODO(roosa): Inline.
        return mBounds.getBounds();
    }

    @Override
    public int hashCode() {
        int result = mSafeInsets.hashCode();
        result = result * 31 + mBoundingRect.hashCode();
        result = result * 31 + mBoundingPolygon.hashCode();
        result = result * 31 + mBounds.getBounds().hashCode();
        return result;
    }

@@ -152,8 +142,7 @@ public final class DisplayCutout {
        if (o instanceof DisplayCutout) {
            DisplayCutout c = (DisplayCutout) o;
            return mSafeInsets.equals(c.mSafeInsets)
                    && mBoundingRect.equals(c.mBoundingRect)
                    && mBoundingPolygon.equals(c.mBoundingPolygon);
                    && mBounds.equals(c.mBounds);
        }
        return false;
    }
@@ -161,7 +150,7 @@ public final class DisplayCutout {
    @Override
    public String toString() {
        return "DisplayCutout{insets=" + mSafeInsets
                + " bounding=" + mBoundingRect
                + " bounds=" + mBounds
                + "}";
    }

@@ -172,15 +161,13 @@ public final class DisplayCutout {
     * @hide
     */
    public DisplayCutout inset(int insetLeft, int insetTop, int insetRight, int insetBottom) {
        if (mBoundingRect.isEmpty()
        if (mBounds.isEmpty()
                || insetLeft == 0 && insetTop == 0 && insetRight == 0 && insetBottom == 0) {
            return this;
        }

        Rect safeInsets = new Rect(mSafeInsets);
        Rect boundingRect = new Rect(mBoundingRect);
        ArrayList<Point> boundingPolygon = new ArrayList<>();
        getBoundingPolygon(boundingPolygon);
        Region bounds = Region.obtain(mBounds);

        // Note: it's not really well defined what happens when the inset is negative, because we
        // don't know if the safe inset needs to expand in general.
@@ -197,10 +184,9 @@ public final class DisplayCutout {
            safeInsets.right = atLeastZero(safeInsets.right - insetRight);
        }

        boundingRect.offset(-insetLeft, -insetTop);
        offset(boundingPolygon, -insetLeft, -insetTop);
        bounds.translate(-insetLeft, -insetTop);

        return new DisplayCutout(safeInsets, boundingRect, boundingPolygon);
        return new DisplayCutout(safeInsets, bounds);
    }

    /**
@@ -210,20 +196,17 @@ public final class DisplayCutout {
     * @hide
     */
    public DisplayCutout calculateRelativeTo(Rect frame) {
        if (mBoundingRect.isEmpty() || !Rect.intersects(frame, mBoundingRect)) {
        if (mBounds.isEmpty() || !Rect.intersects(frame, mBounds.getBounds())) {
            return NO_CUTOUT;
        }

        Rect boundingRect = new Rect(mBoundingRect);
        ArrayList<Point> boundingPolygon = new ArrayList<>();
        getBoundingPolygon(boundingPolygon);

        return DisplayCutout.calculateRelativeTo(frame, boundingRect, boundingPolygon);
        return DisplayCutout.calculateRelativeTo(frame, Region.obtain(mBounds));
    }

    private static DisplayCutout calculateRelativeTo(Rect frame, Rect boundingRect,
            ArrayList<Point> boundingPolygon) {
    private static DisplayCutout calculateRelativeTo(Rect frame, Region bounds) {
        Rect boundingRect = bounds.getBounds();
        Rect safeRect = new Rect();

        int bestArea = 0;
        int bestVariant = 0;
        for (int variant = ROTATION_0; variant <= ROTATION_270; variant++) {
@@ -247,10 +230,9 @@ public final class DisplayCutout {
                    Math.max(0, frame.bottom - safeRect.bottom));
        }

        boundingRect.offset(-frame.left, -frame.top);
        offset(boundingPolygon, -frame.left, -frame.top);
        bounds.translate(-frame.left, -frame.top);

        return new DisplayCutout(safeRect, boundingRect, boundingPolygon);
        return new DisplayCutout(safeRect, bounds);
    }

    private static int calculateInsetVariantArea(Rect frame, Rect boundingRect, int variant,
@@ -277,11 +259,6 @@ public final class DisplayCutout {
        return value < 0 ? 0 : value;
    }

    private static void offset(ArrayList<Point> points, int dx, int dy) {
        for (int i = 0; i < points.size(); i++) {
            points.get(i).offset(dx, dy);
        }
    }

    /**
     * Creates an instance from a bounding polygon.
@@ -289,20 +266,28 @@ public final class DisplayCutout {
     * @hide
     */
    public static DisplayCutout fromBoundingPolygon(List<Point> points) {
        Rect boundingRect = new Rect(Integer.MAX_VALUE, Integer.MAX_VALUE,
                Integer.MIN_VALUE, Integer.MIN_VALUE);
        ArrayList<Point> boundingPolygon = new ArrayList<>();
        Region bounds = Region.obtain();
        Path path = new Path();

        path.reset();
        for (int i = 0; i < points.size(); i++) {
            Point point = points.get(i);
            boundingRect.left = Math.min(boundingRect.left, point.x);
            boundingRect.right = Math.max(boundingRect.right, point.x);
            boundingRect.top = Math.min(boundingRect.top, point.y);
            boundingRect.bottom = Math.max(boundingRect.bottom, point.y);
            boundingPolygon.add(new Point(point));
            if (i == 0) {
                path.moveTo(point.x, point.y);
            } else {
                path.lineTo(point.x, point.y);
            }
        }
        path.close();

        RectF clipRect = new RectF();
        path.computeBounds(clipRect, false /* unused */);
        Region clipRegion = Region.obtain();
        clipRegion.set((int) clipRect.left, (int) clipRect.top,
                (int) clipRect.right, (int) clipRect.bottom);

        return new DisplayCutout(ZERO_RECT, boundingRect, boundingPolygon);
        bounds.setPath(path, clipRegion);
        return new DisplayCutout(ZERO_RECT, bounds);
    }

    /**
@@ -336,8 +321,7 @@ public final class DisplayCutout {
            } else {
                out.writeInt(1);
                out.writeTypedObject(mInner.mSafeInsets, flags);
                out.writeTypedObject(mInner.mBoundingRect, flags);
                out.writeTypedList(mInner.mBoundingPolygon, flags);
                out.writeTypedObject(mInner.mBounds, flags);
            }
        }

@@ -368,13 +352,10 @@ public final class DisplayCutout {
                return NO_CUTOUT;
            }

            ArrayList<Point> boundingPolygon = new ArrayList<>();

            Rect safeInsets = in.readTypedObject(Rect.CREATOR);
            Rect boundingRect = in.readTypedObject(Rect.CREATOR);
            in.readTypedList(boundingPolygon, Point.CREATOR);
            Region bounds = in.readTypedObject(Region.CREATOR);

            return new DisplayCutout(safeInsets, boundingRect, boundingPolygon);
            return new DisplayCutout(safeInsets, bounds);
        }

        public DisplayCutout get() {
+1 −1
Original line number Diff line number Diff line
@@ -1602,7 +1602,7 @@ public final class ViewRootImpl implements ViewParent,
        if (!layoutInCutout) {
            // Window is either not laid out in cutout or the status bar inset takes care of
            // clearing the cutout, so we don't need to dispatch the cutout to the hierarchy.
            insets = insets.consumeCutout();
            insets = insets.consumeDisplayCutout();
        }
        host.dispatchApplyWindowInsets(insets);
    }
+16 −15
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@

package android.view;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;

/**
@@ -49,7 +49,7 @@ public final class WindowInsets {
    private boolean mSystemWindowInsetsConsumed = false;
    private boolean mWindowDecorInsetsConsumed = false;
    private boolean mStableInsetsConsumed = false;
    private boolean mCutoutConsumed = false;
    private boolean mDisplayCutoutConsumed = false;

    private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);

@@ -80,8 +80,9 @@ public final class WindowInsets {
        mIsRound = isRound;
        mAlwaysConsumeNavBar = alwaysConsumeNavBar;

        mCutoutConsumed = displayCutout == null;
        mDisplayCutout = mCutoutConsumed ? DisplayCutout.NO_CUTOUT : displayCutout;
        mDisplayCutoutConsumed = displayCutout == null;
        mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
                ? null : displayCutout;
    }

    /**
@@ -99,7 +100,7 @@ public final class WindowInsets {
        mIsRound = src.mIsRound;
        mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar;
        mDisplayCutout = src.mDisplayCutout;
        mCutoutConsumed = src.mCutoutConsumed;
        mDisplayCutoutConsumed = src.mDisplayCutoutConsumed;
    }

    /** @hide */
@@ -269,15 +270,16 @@ public final class WindowInsets {
     */
    public boolean hasInsets() {
        return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets()
                || mDisplayCutout.hasCutout();
                || mDisplayCutout != null;
    }

    /**
     * @return the display cutout
     * Returns the display cutout if there is one.
     *
     * @return the display cutout or null if there is none
     * @see DisplayCutout
     * @hide pending API
     */
    @NonNull
    @Nullable
    public DisplayCutout getDisplayCutout() {
        return mDisplayCutout;
    }
@@ -286,12 +288,11 @@ public final class WindowInsets {
     * Returns a copy of this WindowInsets with the cutout fully consumed.
     *
     * @return A modified copy of this WindowInsets
     * @hide pending API
     */
    public WindowInsets consumeCutout() {
    public WindowInsets consumeDisplayCutout() {
        final WindowInsets result = new WindowInsets(this);
        result.mDisplayCutout = DisplayCutout.NO_CUTOUT;
        result.mCutoutConsumed = true;
        result.mDisplayCutout = null;
        result.mDisplayCutoutConsumed = true;
        return result;
    }

@@ -311,7 +312,7 @@ public final class WindowInsets {
     */
    public boolean isConsumed() {
        return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed
                && mCutoutConsumed;
                && mDisplayCutoutConsumed;
    }

    /**
@@ -530,7 +531,7 @@ public final class WindowInsets {
        return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets
                + " windowDecorInsets=" + mWindowDecorInsets
                + " stableInsets=" + mStableInsets
                + (mDisplayCutout.hasCutout() ? " cutout=" + mDisplayCutout : "")
                + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
                + (isRound() ? " round" : "")
                + "}";
    }
+11 −2
Original line number Diff line number Diff line
@@ -1286,7 +1286,6 @@ public interface WindowManager extends ViewManager {
         * The window must correctly position its contents to take the display cutout into account.
         *
         * @see DisplayCutout
         * @hide for now
         */
        public static final long FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA = 0x00000001;

@@ -1294,7 +1293,6 @@ public interface WindowManager extends ViewManager {
         * Various behavioral options/flags.  Default is none.
         *
         * @see #FLAG2_LAYOUT_IN_DISPLAY_CUTOUT_AREA
         * @hide for now
         */
        @Flags2 public long flags2;

@@ -2249,6 +2247,7 @@ public interface WindowManager extends ViewManager {
            out.writeInt(y);
            out.writeInt(type);
            out.writeInt(flags);
            out.writeLong(flags2);
            out.writeInt(privateFlags);
            out.writeInt(softInputMode);
            out.writeInt(gravity);
@@ -2304,6 +2303,7 @@ public interface WindowManager extends ViewManager {
            y = in.readInt();
            type = in.readInt();
            flags = in.readInt();
            flags2 = in.readLong();
            privateFlags = in.readInt();
            softInputMode = in.readInt();
            gravity = in.readInt();
@@ -2436,6 +2436,10 @@ public interface WindowManager extends ViewManager {
                flags = o.flags;
                changes |= FLAGS_CHANGED;
            }
            if (flags2 != o.flags2) {
                flags2 = o.flags2;
                changes |= FLAGS_CHANGED;
            }
            if (privateFlags != o.privateFlags) {
                privateFlags = o.privateFlags;
                changes |= PRIVATE_FLAGS_CHANGED;
@@ -2689,6 +2693,11 @@ public interface WindowManager extends ViewManager {
            sb.append(System.lineSeparator());
            sb.append(prefix).append("  fl=").append(
                    ViewDebug.flagsToString(LayoutParams.class, "flags", flags));
            if (flags2 != 0) {
                sb.append(System.lineSeparator());
                // TODO(roosa): add a long overload for ViewDebug.flagsToString.
                sb.append(prefix).append("  fl2=0x").append(Long.toHexString(flags2));
            }
            if (privateFlags != 0) {
                sb.append(System.lineSeparator());
                sb.append(prefix).append("  pfl=").append(ViewDebug.flagsToString(
Loading