Clean up Outline API, method on drawable

bug:15025466
bug:15089680
Change-Id: I8d3b64a0d9dbdbaf679042c8b384d2050323a8e6
diff --git a/api/current.txt b/api/current.txt
index ebd3605..5b36763 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10196,10 +10196,10 @@
     ctor public Outline();
     ctor public Outline(android.graphics.Outline);
     method public boolean canClip();
-    method public boolean isValid();
-    method public void reset();
+    method public boolean isEmpty();
     method public void set(android.graphics.Outline);
     method public void setConvexPath(android.graphics.Path);
+    method public void setEmpty();
     method public void setOval(int, int, int, int);
     method public void setOval(android.graphics.Rect);
     method public void setRect(int, int, int, int);
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index b2839cb..cf125bc 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -366,10 +366,8 @@
      * Deep copies the data into native to simplify reference ownership.
      */
     public void setOutline(Outline outline) {
-        if (outline == null) {
+        if (outline == null || outline.isEmpty()) {
             nSetOutlineEmpty(mNativeRenderNode);
-        } else if (!outline.isValid()) {
-            throw new IllegalArgumentException("Outline must be valid");
         } else if (outline.mRect != null) {
             nSetOutlineRoundRect(mNativeRenderNode, outline.mRect.left, outline.mRect.top,
                     outline.mRect.right, outline.mRect.bottom, outline.mRadius);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6dc7286..0f21c1d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10680,24 +10680,30 @@
     }
 
     /**
-     * Sets the outline of the view, which defines the shape of the shadow it
-     * casts.
+     * Sets the {@link Outline} of the view, which defines the shape of the shadow it
+     * casts, and enables outline clipping.
      * <p>
-     * If the outline is not set or is null, shadows will be cast from the
+     * By default, a View queries its Outline from its background drawable, via
+     * {@link Drawable#getOutline(Outline)}. Manually setting the Outline with this method allows
+     * this behavior to be overridden.
+     * <p>
+     * If the outline is empty or is null, shadows will be cast from the
      * bounds of the View.
+     * <p>
+     * Only outlines that return true from {@link Outline#canClip()} may be used for clipping.
      *
      * @param outline The new outline of the view.
-     *         Must be {@link android.graphics.Outline#isValid() valid.}
+     *
+     * @see #setClipToOutline(boolean)
+     * @see #getClipToOutline()
      */
     public void setOutline(@Nullable Outline outline) {
-        if (outline != null && !outline.isValid()) {
-            throw new IllegalArgumentException("Outline must not be invalid");
-        }
-
         mPrivateFlags3 |= PFLAG3_OUTLINE_DEFINED;
 
-        if (outline == null) {
-            mOutline = null;
+        if (outline == null || outline.isEmpty()) {
+            if (mOutline != null) {
+                mOutline.setEmpty();
+            }
         } else {
             // always copy the path since caller may reuse
             if (mOutline == null) {
@@ -10708,12 +10714,30 @@
         mRenderNode.setOutline(mOutline);
     }
 
+    /**
+     * Returns whether the Outline should be used to clip the contents of the View.
+     * <p>
+     * Note that this flag will only be respected if the View's Outline returns true from
+     * {@link Outline#canClip()}.
+     *
+     * @see #setOutline(Outline)
+     * @see #setClipToOutline(boolean)
+     */
     public final boolean getClipToOutline() {
         return mRenderNode.getClipToOutline();
     }
 
+    /**
+     * Sets whether the View's Outline should be used to clip the contents of the View.
+     * <p>
+     * Note that this flag will only be respected if the View's Outline returns true from
+     * {@link Outline#canClip()}.
+     *
+     * @see #setOutline(Outline)
+     * @see #getClipToOutline()
+     */
     public void setClipToOutline(boolean clipToOutline) {
-        // TODO: add a fast invalidation here
+        damageInParent();
         if (getClipToOutline() != clipToOutline) {
             mRenderNode.setClipToOutline(clipToOutline);
         }
@@ -10726,10 +10750,10 @@
                 mOutline = new Outline();
             } else {
                 //invalidate outline, to ensure background calculates it
-                mOutline.reset();
+                mOutline.setEmpty();
             }
             if (mBackground.getOutline(mOutline)) {
-                if (!mOutline.isValid()) {
+                if (mOutline.isEmpty()) {
                     throw new IllegalStateException("Background drawable failed to build outline");
                 }
                 mRenderNode.setOutline(mOutline);
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index c6ba75c..d87c3cb 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -23,9 +23,9 @@
 
 /**
  * Defines a simple shape, used for bounding graphical regions.
- *
+ * <p>
  * Can be used with a View, or computed by a Drawable, to drive the shape of shadows cast by a
- * View.
+ * View, or to clip the contents of the View.
  *
  * @see View#setOutline(Outline)
  * @see Drawable#getOutline(Outline)
@@ -41,7 +41,7 @@
     public Path mPath;
 
     /**
-     * Constructs an invalid Outline. Call one of the setter methods to make
+     * Constructs an empty Outline. Call one of the setter methods to make
      * the outline valid for use with a View.
      */
     public Outline() {}
@@ -49,23 +49,31 @@
     /**
      * Constructs an Outline with a copy of the data in src.
      */
-    public Outline(@Nullable Outline src) {
+    public Outline(@NonNull Outline src) {
         set(src);
     }
 
-    public void reset() {
+    /**
+     * Sets the outline to be empty.
+     *
+     * @see #isEmpty()
+     */
+    public void setEmpty() {
         mRadius = 0;
         mRect = null;
         mPath = null;
     }
 
     /**
-     * Returns whether the Outline is valid for use with a View.
+     * Returns whether the Outline is empty.
      * <p>
-     * Outlines are invalid when constructed until a setter method is called.
+     * Outlines are empty when constructed, or if {@link #setEmpty()} is called,
+     * until a setter method is called
+     *
+     * @see #setEmpty()
      */
-    public boolean isValid() {
-        return mRect != null || mPath != null;
+    public boolean isEmpty() {
+        return mRect == null && mPath == null;
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index c78096a..951add9 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -16,6 +16,7 @@
 
 package android.graphics.drawable;
 
+import android.annotation.NonNull;
 import android.graphics.Insets;
 import android.graphics.Xfermode;
 import android.os.Trace;
@@ -817,11 +818,12 @@
     /**
      * Return in padding the insets suggested by this Drawable for placing
      * content inside the drawable's bounds. Positive values move toward the
-     * center of the Drawable (set Rect.inset). Returns true if this drawable
-     * actually has a padding, else false. When false is returned, the padding
-     * is always set to 0.
+     * center of the Drawable (set Rect.inset).
+     *
+     * @return true if this drawable actually has a padding, else false. When false is returned,
+     * the padding is always set to 0.
      */
-    public boolean getPadding(Rect padding) {
+    public boolean getPadding(@NonNull Rect padding) {
         padding.set(0, 0, 0, 0);
         return false;
     }
@@ -842,13 +844,16 @@
      * This method will be called by a View on its background Drawable after bounds change, or its
      * Drawable is invalidated, if the View's Outline isn't set explicitly. This allows the
      * background Drawable to define the shape of the shadow cast by the View.
-     *
+     * <p>
      * The default behavior defines the outline to be the bounding rectangle. Subclasses that wish
      * to convey a different shape must override this method.
      *
+     * @return true if this drawable actually has an outline, else false. The outline must be
+     *         populated by the drawable if true is returned.
+     *
      * @see View#setOutline(android.graphics.Outline)
      */
-    public boolean getOutline(Outline outline) {
+    public boolean getOutline(@NonNull Outline outline) {
         outline.setRect(getBounds());
         return true;
     }