Adds setCornerRadius to ActivityView & SurfaceView

Applies corner radius to Bubbles when expanded, based on
dialogCornerRadius theme attribute.

Test: manual -- Enable Bubbles, add one and expand, observe corners
Bug: 123545569
Change-Id: I88162a974534786b4ac8bed4e0fa1302bded9096
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 864af8c..4771f9f 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -189,6 +189,17 @@
     }
 
     /**
+     * Sets the corner radius for the Activity displayed here. The corners will be
+     * cropped from the window painted by the contained Activity.
+     *
+     * @param cornerRadius the radius for the corners, in pixels
+     * @hide
+     */
+    public void setCornerRadius(float cornerRadius) {
+        mSurfaceView.setCornerRadius(cornerRadius);
+    }
+
+    /**
      * Launch a new activity into this container.
      * <p>Activity resolved by the provided {@link Intent} must have
      * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 7fdda2a..254d04e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -24,8 +24,10 @@
 import android.content.Context;
 import android.content.res.CompatibilityInfo.Translator;
 import android.content.res.Configuration;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
@@ -127,6 +129,8 @@
     final Rect mTmpRect = new Rect();
     final Configuration mConfiguration = new Configuration();
 
+    Paint mRoundedViewportPaint;
+
     int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -180,6 +184,7 @@
     int mWindowSpaceTop = -1;
     int mSurfaceWidth = -1;
     int mSurfaceHeight = -1;
+    float mCornerRadius;
     @UnsupportedAppUsage
     int mFormat = -1;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -395,7 +400,7 @@
             // draw() is not called when SKIP_DRAW is set
             if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
                 // punch a whole in the view-hierarchy below us
-                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+                clearSurfaceViewPort(canvas);
             }
         }
         super.draw(canvas);
@@ -407,12 +412,39 @@
             // draw() is not called when SKIP_DRAW is set
             if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                 // punch a whole in the view-hierarchy below us
-                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+                clearSurfaceViewPort(canvas);
             }
         }
         super.dispatchDraw(canvas);
     }
 
+    private void clearSurfaceViewPort(Canvas canvas) {
+        if (mCornerRadius > 0f) {
+            canvas.getClipBounds(mTmpRect);
+            canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
+                    mCornerRadius, mCornerRadius, mRoundedViewportPaint);
+        } else {
+            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+        }
+    }
+
+    /**
+     * Sets the corner radius for the SurfaceView. This will round both the corners of the
+     * underlying surface, as well as the corners of the hole created to expose the surface.
+     *
+     * @param cornerRadius the new radius of the corners in pixels
+     * @hide
+     */
+    public void setCornerRadius(float cornerRadius) {
+        mCornerRadius = cornerRadius;
+        if (mCornerRadius > 0f && mRoundedViewportPaint == null) {
+            mRoundedViewportPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            mRoundedViewportPaint.setBlendMode(BlendMode.CLEAR);
+            mRoundedViewportPaint.setColor(0);
+        }
+        invalidate();
+    }
+
     /**
      * Control whether the surface view's surface is placed on top of another
      * regular surface view in the window (but still behind the window itself).
@@ -634,6 +666,7 @@
                             // size.
                             mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
                         }
+                        mSurfaceControl.setCornerRadius(mCornerRadius);
                         if (sizeChanged && !creating) {
                             mSurfaceControl.setBufferSize(mSurfaceWidth, mSurfaceHeight);
                         }
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index d4bf9cd..9b72e7a 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -151,5 +151,11 @@
         <attr name="optedOut" format="boolean" />
     </declare-styleable>
 
+    <!-- Theme attributes used to style the appearance of expanded Bubbles -->
+    <declare-styleable name="BubbleExpandedView">
+        <attr name="android:colorBackgroundFloating" />
+        <attr name="android:dialogCornerRadius" />
+    </declare-styleable>
+
 </resources>
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 39867c3..afe1f46 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -52,6 +52,7 @@
 import android.view.WindowInsets;
 import android.widget.LinearLayout;
 
+import com.android.internal.policy.ScreenDecorationsUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.recents.TriangleShape;
@@ -87,6 +88,7 @@
     private int mBubbleHeight;
     private int mPointerWidth;
     private int mPointerHeight;
+    private ShapeDrawable mPointerDrawable;
 
     private NotificationEntry mEntry;
     private PackageManager mPm;
@@ -170,16 +172,10 @@
         mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
         mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
 
-        TypedArray ta = getContext().obtainStyledAttributes(
-                new int[] {android.R.attr.colorBackgroundFloating});
-        int bgColor = ta.getColor(0, Color.WHITE);
-        ta.recycle();
 
-        ShapeDrawable triangleDrawable = new ShapeDrawable(TriangleShape.create(
+        mPointerDrawable = new ShapeDrawable(TriangleShape.create(
                 mPointerWidth, mPointerHeight, false /* pointUp */));
-
-        triangleDrawable.setTint(bgColor);
-        mPointerView.setBackground(triangleDrawable);
+        mPointerView.setBackground(mPointerDrawable);
 
         mSettingsIconHeight = getContext().getResources().getDimensionPixelSize(
                 R.dimen.bubble_expanded_header_height);
@@ -193,6 +189,8 @@
         // Make sure pointer is below activity view
         bringChildToFront(mPointerView);
 
+        applyThemeAttrs();
+
         setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
             // Keep track of IME displaying because we should not make any adjustments that might
             // cause a config change while the IME is displayed otherwise it'll loose focus.
@@ -206,6 +204,23 @@
         });
     }
 
+    void applyThemeAttrs() {
+        TypedArray ta = getContext().obtainStyledAttributes(R.styleable.BubbleExpandedView);
+        int bgColor = ta.getColor(
+                R.styleable.BubbleExpandedView_android_colorBackgroundFloating, Color.WHITE);
+        float cornerRadius = ta.getDimension(
+                R.styleable.BubbleExpandedView_android_dialogCornerRadius, 0);
+        ta.recycle();
+
+        // Update triangle color.
+        mPointerDrawable.setTint(bgColor);
+
+        // Update ActivityView cornerRadius
+        if (ScreenDecorationsUtils.supportsRoundedCornersOnWindows(mContext.getResources())) {
+            mActivityView.setCornerRadius(cornerRadius);
+        }
+    }
+
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
@@ -267,7 +282,7 @@
         if (mAppIcon == null) {
             mAppIcon = mPm.getDefaultActivityIcon();
         }
-        updateTheme();
+        applyThemeAttrs();
         showSettingsIcon();
         updateExpandedView();
     }
@@ -307,21 +322,6 @@
         }
     }
 
-    void updateTheme() {
-        // Get new colors.
-        TypedArray ta = mContext.obtainStyledAttributes(
-                new int[]{android.R.attr.colorBackgroundFloating, android.R.attr.colorForeground});
-        int backgroundColor = ta.getColor(0, Color.WHITE /* default */);
-        int foregroundColor = ta.getColor(1, Color.BLACK /* default */);
-        ta.recycle();
-
-        // Update triangle color.
-        ShapeDrawable triangleDrawable = new ShapeDrawable(
-                TriangleShape.create(mPointerWidth, mPointerHeight, false /* pointUp */));
-        triangleDrawable.setTint(backgroundColor);
-        mPointerView.setBackground(triangleDrawable);
-    }
-
     private void updateExpandedView() {
         mBubbleIntent = getBubbleIntent(mEntry);
         if (mBubbleIntent != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 4fef157..4a889c5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -447,7 +447,7 @@
     public void onThemeChanged() {
         for (Bubble b: mBubbleData.getBubbles()) {
             b.iconView.updateViews();
-            b.expandedView.updateTheme();
+            b.expandedView.applyThemeAttrs();
         }
     }