DisplayCutout: Support more than one cutout

Also makes API more restrictive. Also moves window manager specific
logic out of the framework. Also fixes SystemUI such that it can properly
deal with more than one cutout.

Bug: 74195186
Test: atest DisplayCutoutTest WmDisplayCutoutTest DisplayContentTests WindowFrameTests
Change-Id: Ib7b89e119ce2d3961687579bb81eadce1159a600
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 903f3aa..ec2390f 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -31,6 +31,7 @@
 import android.graphics.Path;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.provider.Settings.Secure;
 import android.support.annotation.VisibleForTesting;
@@ -312,6 +313,7 @@
 
         private final DisplayInfo mInfo = new DisplayInfo();
         private final Paint mPaint = new Paint();
+        private final Region mBounds = new Region();
         private final Rect mBoundingRect = new Rect();
         private final Path mBoundingPath = new Path();
         private final int[] mLocation = new int[2];
@@ -370,11 +372,13 @@
         private void update() {
             requestLayout();
             getDisplay().getDisplayInfo(mInfo);
+            mBounds.setEmpty();
             mBoundingRect.setEmpty();
             mBoundingPath.reset();
             int newVisible;
             if (hasCutout()) {
-                mBoundingRect.set(mInfo.displayCutout.getBoundingRect());
+                mBounds.set(mInfo.displayCutout.getBounds());
+                localBounds(mBoundingRect);
                 mInfo.displayCutout.getBounds().getBoundaryPath(mBoundingPath);
                 newVisible = VISIBLE;
             } else {
@@ -402,7 +406,7 @@
 
         @Override
         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            if (mBoundingRect.isEmpty()) {
+            if (mBounds.isEmpty()) {
                 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                 return;
             }
@@ -410,5 +414,50 @@
                     resolveSizeAndState(mBoundingRect.width(), widthMeasureSpec, 0),
                     resolveSizeAndState(mBoundingRect.height(), heightMeasureSpec, 0));
         }
+
+        public static void boundsFromDirection(DisplayCutout displayCutout, int gravity, Rect out) {
+            Region bounds = displayCutout.getBounds();
+            switch (gravity) {
+                case Gravity.TOP:
+                    bounds.op(0, 0, Integer.MAX_VALUE, displayCutout.getSafeInsetTop(),
+                            Region.Op.INTERSECT);
+                    out.set(bounds.getBounds());
+                    break;
+                case Gravity.LEFT:
+                    bounds.op(0, 0, displayCutout.getSafeInsetLeft(), Integer.MAX_VALUE,
+                            Region.Op.INTERSECT);
+                    out.set(bounds.getBounds());
+                    break;
+                case Gravity.BOTTOM:
+                    bounds.op(0, displayCutout.getSafeInsetTop() + 1, Integer.MAX_VALUE,
+                            Integer.MAX_VALUE, Region.Op.INTERSECT);
+                    out.set(bounds.getBounds());
+                    break;
+                case Gravity.RIGHT:
+                    bounds.op(displayCutout.getSafeInsetLeft() + 1, 0, Integer.MAX_VALUE,
+                            Integer.MAX_VALUE, Region.Op.INTERSECT);
+                    out.set(bounds.getBounds());
+                    break;
+            }
+            bounds.recycle();
+        }
+
+        private void localBounds(Rect out) {
+            final DisplayCutout displayCutout = mInfo.displayCutout;
+
+            if (mStart) {
+                if (displayCutout.getSafeInsetLeft() > 0) {
+                    boundsFromDirection(displayCutout, Gravity.LEFT, out);
+                } else if (displayCutout.getSafeInsetTop() > 0) {
+                    boundsFromDirection(displayCutout, Gravity.TOP, out);
+                }
+            } else {
+                if (displayCutout.getSafeInsetRight() > 0) {
+                    boundsFromDirection(displayCutout, Gravity.RIGHT, out);
+                } else if (displayCutout.getSafeInsetBottom() > 0) {
+                    boundsFromDirection(displayCutout, Gravity.BOTTOM, out);
+                }
+            }
+        }
     }
 }