Merge "Remote layoutlib updates to support the API changes" into qt-dev
diff --git a/bridge/src/android/view/ViewGroup_Delegate.java b/bridge/src/android/view/ViewGroup_Delegate.java
index 81bc083..a34ef22 100644
--- a/bridge/src/android/view/ViewGroup_Delegate.java
+++ b/bridge/src/android/view/ViewGroup_Delegate.java
@@ -108,7 +108,7 @@
         Rect clipBounds = canvas.getClipBounds();
         Rect newBounds = new Rect(clipBounds);
         newBounds.inset((int)-elevation, (int)-elevation);
-        canvas.clipRect(newBounds, Op.REPLACE);
+        canvas.clipRectUnion(newBounds);
         canvas.drawBitmap(bitmap, 0, 0, null);
         canvas.restore();
     }
diff --git a/bridge/src/android/view/shadow/HighQualityShadowPainter.java b/bridge/src/android/view/shadow/HighQualityShadowPainter.java
index a226f75..dd555c5 100644
--- a/bridge/src/android/view/shadow/HighQualityShadowPainter.java
+++ b/bridge/src/android/view/shadow/HighQualityShadowPainter.java
@@ -19,13 +19,12 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Outline;
+import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
 import android.view.ViewGroup;
 
-import java.util.ArrayList;
-import java.util.List;
-
+import static android.view.shadow.ShadowConstants.MIN_ALPHA;
 import static android.view.shadow.ShadowConstants.SCALE_DOWN;
 
 public class HighQualityShadowPainter {
@@ -45,27 +44,33 @@
         int width = parent.getWidth() / SCALE_DOWN;
         int height = parent.getHeight() / SCALE_DOWN;
 
-        Rect rectBound = new Rect();
-        if (!outline.getRect(rectBound)) {
+        Rect rectOriginal = new Rect();
+        Rect rectScaled = new Rect();
+        if (!outline.getRect(rectScaled) || alpha < MIN_ALPHA) {
+            // If alpha below MIN_ALPHA it's invisible (based on manual test). Save some perf.
             return;
         }
 
-        rectBound.left /= SCALE_DOWN;
-        rectBound.right /= SCALE_DOWN;
-        rectBound.top /= SCALE_DOWN;
-        rectBound.bottom /= SCALE_DOWN;
+        outline.getRect(rectOriginal);
+
+        rectScaled.left /= SCALE_DOWN;
+        rectScaled.right /= SCALE_DOWN;
+        rectScaled.top /= SCALE_DOWN;
+        rectScaled.bottom /= SCALE_DOWN;
         float radius = outline.getRadius() / SCALE_DOWN;
 
-        if (radius > rectBound.width() || radius > rectBound.height()) {
+        if (radius > rectScaled.width() || radius > rectScaled.height()) {
             // Rounded edge generation fails if radius is bigger than drawing box.
             return;
         }
 
-        float[] poly = getPoly(rectBound, elevation / SCALE_DOWN, radius);
+        // ensure alpha doesn't go over 1
+        alpha = (alpha > 1.0f) ? 1.0f : alpha;
+        float[] poly = getPoly(rectScaled, elevation / SCALE_DOWN, radius);
 
-        paintAmbientShadow(poly, canvas, width, height);
-        paintSpotShadow(poly, rectBound, elevation / SCALE_DOWN,
-                canvas, alpha, densityDpi, width, height);
+        paintAmbientShadow(poly, canvas, width, height, alpha, rectOriginal, radius);
+        paintSpotShadow(poly, rectScaled, elevation / SCALE_DOWN,
+                canvas, densityDpi, width, height, alpha, rectOriginal, radius);
     }
 
     /**
@@ -84,7 +89,17 @@
         return true;
     }
 
-    private static void paintAmbientShadow(float[] polygon, Canvas canvas, int width, int height) {
+    /**
+     * @param polygon - polygon of the shadow caster
+     * @param canvas - canvas to draw
+     * @param width - scaled canvas (parent) width
+     * @param height - scaled canvas (parent) height
+     * @param alpha - 0-1 scale
+     * @param shadowCasterOutline - unscaled original shadow caster outline.
+     * @param radius
+     */
+    private static void paintAmbientShadow(float[] polygon, Canvas canvas, int width, int height,
+            float alpha, Rect shadowCasterOutline, float radius) {
         // TODO: Consider re-using the triangle buffer here since the world stays consistent.
         // TODO: Reduce the buffer size based on shadow bounds.
 
@@ -93,7 +108,7 @@
                 .setPolygon(polygon)
                 .setEdgeScale(ShadowConstants.AMBIENT_SHADOW_EDGE_SCALE)
                 .setShadowBoundRatio(ShadowConstants.AMBIENT_SHADOW_SHADOW_BOUND)
-                .setShadowStrength(ShadowConstants.AMBIENT_SHADOW_STRENGTH)
+                .setShadowStrength(ShadowConstants.AMBIENT_SHADOW_STRENGTH * alpha)
                 .setRays(ShadowConstants.AMBIENT_SHADOW_RAYS)
                 .setLayers(ShadowConstants.AMBIENT_SHADOW_LAYERS)
                 .build();
@@ -105,12 +120,25 @@
             return;
         }
 
-        drawScaled(canvas, generator.getBitmap(), (int) generator.getTranslateX(),
-                (int) generator.getTranslateY(), width, height);
+        drawScaled(
+                canvas, generator.getBitmap(), (int) generator.getTranslateX(),
+                (int) generator.getTranslateY(), width, height,
+                shadowCasterOutline, radius);
     }
 
-    private static void paintSpotShadow(float[] poly, Rect rectBound, float elevation, Canvas canvas, float alpha,
-            float densityDpi, int width, int height) {
+    /**
+     * @param poly - polygon of the shadow caster
+     * @param rectBound - scaled bounds of shadow caster.
+     * @param canvas - canvas to draw
+     * @param width - scaled canvas (parent) width
+     * @param height - scaled canvas (parent) height
+     * @param alpha - 0-1 scale
+     * @param shadowCasterOutline - unscaled original shadow caster outline.
+     * @param radius
+     */
+    private static void paintSpotShadow(float[] poly, Rect rectBound, float elevation, Canvas canvas,
+            float densityDpi, int width, int height, float alpha, Rect shadowCasterOutline,
+            float radius) {
 
         // TODO: Use alpha later
         float lightZHeightPx = ShadowConstants.SPOT_SHADOW_LIGHT_Z_HEIGHT_DP * (densityDpi / DisplayMetrics.DENSITY_DEFAULT);
@@ -132,7 +160,7 @@
                 .setLightCoord(lightX, lightY, lightZHeightPx)
                 .setLightRadius(dynamicLightRadius)
                 .setLightSourcePoints(ShadowConstants.SPOT_SHADOW_LIGHT_SOURCE_POINTS)
-                .setShadowStrength(ShadowConstants.SPOT_SHADOW_STRENGTH)
+                .setShadowStrength(ShadowConstants.SPOT_SHADOW_STRENGTH * alpha)
                 .setPolygon(poly, poly.length / ShadowConstants.COORDINATE_SIZE)
                 .build();
 
@@ -144,24 +172,82 @@
         }
 
         drawScaled(canvas, generator.getBitmap(), (int) generator.getTranslateX(),
-                (int) generator.getTranslateY(), width, height);
+                (int) generator.getTranslateY(), width, height, shadowCasterOutline, radius);
     }
 
     /**
      * Draw the bitmap scaled up.
      * @param translateX - offset in x axis by which the bitmap is shifted.
      * @param translateY - offset in y axis by which the bitmap is shifted.
+     * @param width  - scaled width of canvas (parent)
+     * @param height - scaled height of canvas (parent)
+     * @param shadowCaster - unscaled outline of shadow caster
+     * @param radius
      */
     private static void drawScaled(Canvas canvas, Bitmap bitmap, int translateX, int translateY,
-            int width, int height) {
-        Rect dest = new Rect();
-        dest.left = -translateX * SCALE_DOWN;
-        dest.top = -translateY * SCALE_DOWN;
-        dest.right = (width * SCALE_DOWN) + dest.left;
-        dest.bottom = (height * SCALE_DOWN) + dest.top;
+            int width, int height, Rect shadowCaster, float radius) {
+        int unscaledTranslateX = translateX * SCALE_DOWN;
+        int unscaledTranslateY = translateY * SCALE_DOWN;
+
+        // To the canvas
+        Rect dest = new Rect(
+                -unscaledTranslateX,
+                -unscaledTranslateY,
+                (width * SCALE_DOWN) - unscaledTranslateX,
+                (height * SCALE_DOWN) - unscaledTranslateY);
+        Rect destSrc = new Rect(0, 0, width, height);
+
+        if (radius > 0) {
+            // Rounded edge.
+            int save = canvas.save();
+            canvas.drawBitmap(bitmap, destSrc, dest, null);
+            canvas.restoreToCount(save);
+            return;
+        }
+
+        /**
+         * ----------------------------------
+         * |                                |
+         * |              top               |
+         * |                                |
+         * ----------------------------------
+         * |      |                 |       |
+         * | left |  shadow caster  | right |
+         * |      |                 |       |
+         * ----------------------------------
+         * |                                |
+         * |            bottom              |
+         * |                                |
+         * ----------------------------------
+         *
+         * dest == top + left + shadow caster + right + bottom
+         * Visually, canvas.drawBitmap(bitmap, destSrc, dest, paint) would achieve the same result.
+         */
+        Rect left = new Rect(dest.left, shadowCaster.top, shadowCaster.left, shadowCaster.bottom);
+        int leftScaled = left.width() / SCALE_DOWN + destSrc.left;
+
+        Rect top = new Rect(dest.left, dest.top, dest.right, shadowCaster.top);
+        int topScaled = top.height() / SCALE_DOWN + destSrc.top;
+
+        Rect right = new Rect(shadowCaster.right, shadowCaster.top, dest.right,
+                shadowCaster.bottom);
+        int rightScaled = (shadowCaster.right + unscaledTranslateX) / SCALE_DOWN + destSrc.left;
+
+        Rect bottom = new Rect(dest.left, shadowCaster.bottom, dest.right, dest.bottom);
+        int bottomScaled = (bottom.bottom - bottom.height()) / SCALE_DOWN + destSrc.top;
+
+        // calculate parts of the middle ground that can be ignored.
+        Rect leftSrc = new Rect(destSrc.left, topScaled, leftScaled, bottomScaled);
+        Rect topSrc = new Rect(destSrc.left, destSrc.top, destSrc.right, topScaled);
+        Rect rightSrc = new Rect(rightScaled, topScaled, destSrc.right, bottomScaled);
+        Rect bottomSrc = new Rect(destSrc.left, bottomScaled, destSrc.right, destSrc.bottom);
 
         int save = canvas.save();
-        canvas.drawBitmap(bitmap, null, dest, null);
+        Paint paint = new Paint();
+        canvas.drawBitmap(bitmap, leftSrc, left, paint);
+        canvas.drawBitmap(bitmap, topSrc, top, paint);
+        canvas.drawBitmap(bitmap, rightSrc, right, paint);
+        canvas.drawBitmap(bitmap, bottomSrc, bottom, paint);
         canvas.restoreToCount(save);
     }
 
diff --git a/bridge/src/android/view/shadow/ShadowConstants.java b/bridge/src/android/view/shadow/ShadowConstants.java
index ae312df..83617d8 100644
--- a/bridge/src/android/view/shadow/ShadowConstants.java
+++ b/bridge/src/android/view/shadow/ShadowConstants.java
@@ -29,6 +29,8 @@
      */
     public static final int SCALE_DOWN = 5;
 
+    public static final float MIN_ALPHA = 0.2f;
+
     public static final int SPOT_SHADOW_RAYS = 40;
     public static final int SPOT_SHADOW_LAYERS = 1;
     public static final int SPOT_SHADOW_LIGHT_SOURCE_POINTS = 4;
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test_high_quality.png
new file mode 100644
index 0000000..d219a1b
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png b/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
index fdf0ec1..6331256 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality.png
index 19f8c20..1639a1a 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality_rounded_edge.png b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality_rounded_edge.png
new file mode 100644
index 0000000..c5ba2c9
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality_rounded_edge.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_no_shadow.png b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_no_shadow.png
index f0ce69b..c21852c 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_no_shadow.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_no_shadow.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/corner.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/corner.xml
new file mode 100644
index 0000000..d74a750
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/corner.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="#f0f" />
+    <corners android:topLeftRadius="4dp" />
+</shape>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/rounded_edge_rect.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/rounded_edge_rect.xml
new file mode 100644
index 0000000..57f8062
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/rounded_edge_rect.xml
@@ -0,0 +1,22 @@
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<!--<?xml version="1.0" encoding="UTF-8"?>-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#B1BCBE"/>
+    <stroke android:width="3dp" android:color="#B1BCBE" />
+    <corners android:radius="20dp"/>
+    <padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
+</shape>
\ No newline at end of file
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadow_sizes_test.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadow_sizes_test.xml
new file mode 100644
index 0000000..5c53ca0
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadow_sizes_test.xml
@@ -0,0 +1,165 @@
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" >
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+        <Button
+            android:layout_width="100dp"
+            android:layout_height="200dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginLeft="28dp"
+            android:layout_alignParentLeft="true"
+            android:elevation="5.5dp"
+            android:stateListAnimator="@null"
+            android:text="5.5"/>
+        <Button
+            android:layout_width="100dp"
+            android:layout_height="200dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginRight="61dp"
+            android:layout_alignParentRight="true"
+            android:elevation="36dp"
+            android:stateListAnimator="@null"
+            android:text="36"/>
+    </RelativeLayout>
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+        <Button
+            android:layout_width="46dp"
+            android:layout_height="22dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginLeft="103dp"
+            android:layout_alignParentLeft="true"
+            android:elevation="15dp"
+            android:stateListAnimator="@null"
+            android:text="15"/>
+        <Button
+            android:id="@+id/button14"
+            android:layout_width="23dp"
+            android:layout_height="21dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginLeft="54dp"
+            android:layout_alignParentLeft="true"
+            android:elevation="15dp"
+            android:stateListAnimator="@null"
+            android:text="15"/>
+        <Button
+            android:id="@+id/button12"
+            android:layout_width="76dp"
+            android:layout_height="20dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginLeft="176dp"
+            android:layout_alignParentLeft="true"
+            android:elevation="15dp"
+            android:stateListAnimator="@null"
+            android:text="15"/>
+        <Button
+            android:id="@+id/button11"
+            android:layout_width="15dp"
+            android:layout_height="23dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginLeft="28dp"
+            android:layout_alignParentLeft="true"
+            android:elevation="15dp"
+            android:stateListAnimator="@null"
+            android:text="15"/>
+        <Button
+            android:layout_width="39dp"
+            android:layout_height="21dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginStart="278dp"
+            android:layout_marginLeft="278dp"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentStart="true"
+            android:elevation="5dp"
+            android:stateListAnimator="@null"
+            android:text="5"/>
+    </RelativeLayout>
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+        <Button
+            android:layout_width="20dp"
+            android:layout_height="36dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginLeft="136dp"
+            android:layout_alignParentLeft="true"
+            android:elevation="5.5dp"
+            android:stateListAnimator="@null"
+            android:text="5.5"/>
+        <Button
+            android:id="@+id/button17"
+            android:layout_width="22dp"
+            android:layout_height="85dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginLeft="77dp"
+            android:layout_alignParentLeft="true"
+            android:elevation="5.5dp"
+            android:stateListAnimator="@null"
+            android:text="5.5"/>
+        <Button
+            android:id="@+id/button16"
+            android:layout_width="23dp"
+            android:layout_height="131dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginLeft="28dp"
+            android:layout_alignParentLeft="true"
+            android:elevation="5.5dp"
+            android:stateListAnimator="@null"
+            android:text="5.5"/>
+        <Button
+            android:layout_width="33dp"
+            android:layout_height="115dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginRight="155dp"
+            android:layout_alignParentRight="true"
+            android:elevation="36dp"
+            android:stateListAnimator="@null"
+            android:text="36"/>
+        <Button
+            android:id="@+id/button20"
+            android:layout_width="29dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="28dp"
+            android:layout_marginRight="92dp"
+            android:layout_alignParentRight="true"
+            android:elevation="36dp"
+            android:stateListAnimator="@null"
+            android:text="36"/>
+        <Button
+            android:id="@+id/button18"
+            android:layout_width="14dp"
+            android:layout_height="23dp"
+            android:layout_marginTop="28dp"
+            android:layout_marginRight="50dp"
+            android:layout_alignParentRight="true"
+            android:elevation="36dp"
+            android:stateListAnimator="@null"
+            android:text="36"/>
+    </RelativeLayout>
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_rounded_edge_test.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_rounded_edge_test.xml
new file mode 100644
index 0000000..943e103
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_rounded_edge_test.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" >
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+
+        <Button
+            android:layout_marginLeft="40dp"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
+            android:layout_alignParentLeft="true"
+            android:layout_centerVertical="true"
+            android:elevation="48dp"
+            android:stateListAnimator="@null"
+            android:background="@drawable/rounded_edge_rect"/>
+
+        <Button
+            android:layout_marginRight="40dp"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:elevation="48dp"
+            android:background="@drawable/rounded_edge_rect"
+            android:stateListAnimator="@null"/>
+
+    </RelativeLayout>
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+
+        <Button
+            android:layout_marginLeft="40dp"
+            android:layout_width="48dp"
+            android:layout_height="40dp"
+            android:layout_alignParentLeft="true"
+            android:layout_centerVertical="true"
+            android:elevation="0dp"
+            android:background="@drawable/rounded_edge_rect"
+            android:stateListAnimator="@null"/>
+
+        <Button
+            android:layout_marginRight="40dp"
+            android:layout_width="48dp"
+            android:layout_height="40dp"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:elevation="100dp"
+            android:background="@drawable/rounded_edge_rect"
+            android:stateListAnimator="@null"/>
+
+    </RelativeLayout>
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+
+        <Button
+            android:layout_marginLeft="40dp"
+            android:layout_width="40dp"
+            android:layout_height="48dp"
+            android:layout_alignParentLeft="true"
+            android:layout_centerVertical="true"
+            android:elevation="12dp"
+            android:background="@drawable/rounded_edge_rect"
+            android:stateListAnimator="@null"/>
+
+        <Button
+            android:layout_marginRight="40dp"
+            android:layout_width="40dp"
+            android:layout_height="48dp"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:elevation="36dp"
+            android:background="@drawable/rounded_edge_rect"
+            android:stateListAnimator="@null"/>
+
+    </RelativeLayout>
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+        <Button
+            android:layout_marginLeft="40dp"
+            android:layout_width="48dp"
+            android:layout_height="40dp"
+            android:layout_alignParentLeft="true"
+            android:layout_centerVertical="true"
+            android:elevation="12dp"
+            android:stateListAnimator="@null"
+            android:background="@drawable/rounded_edge_rect"
+            android:alpha="0.1"/>
+
+        <Button
+            android:layout_marginRight="40dp"
+            android:layout_width="48dp"
+            android:layout_height="40dp"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:elevation="12dp"
+            android:stateListAnimator="@null"
+            android:background="@drawable/rounded_edge_rect"
+            android:alpha="0.5"/>
+    </RelativeLayout>
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml
index b1e01b8..498a63f 100644
--- a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/shadows_test.xml
@@ -146,7 +146,21 @@
             android:layout_centerVertical="true"
             android:elevation="12dp"
             android:text="12"
+            android:alpha="5"
             android:stateListAnimator="@null" />
 
+        <Button
+            android:translationX="5dp"
+            android:translationY="20dp"
+            android:layout_marginRight="40dp"
+            android:layout_width="48dp"
+            android:layout_height="40dp"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:elevation="12dp"
+            android:text="12"
+            android:stateListAnimator="@null"
+            android:background="@drawable/corner" />
+
     </RelativeLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
index 12ece48..36c09ad 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
@@ -572,7 +572,7 @@
                 .setProjectResources(sProjectResources)
                 .setTheme("AppTheme", true)
                 .setRenderingMode(RenderingMode.NORMAL)
-                .setTargetSdk(22)
+                .setTargetSdk(28)
                 .setFlag(RenderParamsFlags.FLAG_DO_NOT_RENDER_ON_CREATE, true)
                 .setAssetRepository(new TestAssetRepository(TEST_RES_DIR + "/" + APP_TEST_ASSET));
     }
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
index 62678a1..2c91ade 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
@@ -1041,6 +1041,8 @@
                 .build();
 
         renderAndVerify(params, "shadows_test_no_shadow.png");
+        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
+        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
     }
 
     @Test
@@ -1058,6 +1060,8 @@
                 .build();
 
         renderAndVerify(params, "shadows_test.png");
+        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
+        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
     }
 
     @Test
@@ -1075,6 +1079,26 @@
                 .build();
 
         renderAndVerify(params, "shadows_test_high_quality.png");
+        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
+        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
+    }
+
+    @Test
+    public void testHighQualityRoundedEdgeRectangleShadow() throws Exception {
+        LayoutPullParser parser = createParserFromPath("shadows_rounded_edge_test.xml");
+        LayoutLibTestCallback layoutLibCallback =
+                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+        layoutLibCallback.setShadowQuality(true);
+        SessionParams params = getSessionParamsBuilder()
+                .setParser(parser)
+                .setConfigGenerator(ConfigGenerator.NEXUS_5)
+                .setCallback(layoutLibCallback)
+                .build();
+
+        renderAndVerify(params, "shadows_test_high_quality_rounded_edge.png");
+        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
+        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
     }
 
     @Test
@@ -1097,6 +1121,24 @@
     }
 
     @Test
+    public void testHighQualityShadowSizes() throws Exception {
+        LayoutPullParser parser = createParserFromPath("shadow_sizes_test.xml");
+        LayoutLibTestCallback layoutLibCallback =
+                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+        layoutLibCallback.setShadowQuality(true);
+        SessionParams params = getSessionParamsBuilder()
+                .setParser(parser)
+                .setConfigGenerator(ConfigGenerator.NEXUS_5)
+                .setCallback(layoutLibCallback)
+                .build();
+
+        renderAndVerify(params, "shadow_sizes_test_high_quality.png");
+        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
+        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
+    }
+
+    @Test
     public void testResourcesGetIdentifier() throws Exception {
         // Setup
         // Create the layout pull parser for our resources (empty.xml can not be part of the test