Expose StaticLayout.Builder publicly

Expose the new Builder pattern for creating StaticLayout. This allows
access to a number of features that have been available to TextView
through a hidden constructor. Some of these features have existed
for a while (mostly maxLines), while others are new (breakStrategy,
indents).

The builder is cleaner and has a better upgrade path than the old
pattern of lots of constructors with varying numbers of arguments.

Bug: 20190561
Change-Id: Ia3cd124825ab0cb469d22d1fc576ad26454545b8
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 08fcd56..451abea 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import android.annotation.Nullable;
 import android.graphics.Paint;
 import android.text.style.LeadingMarginSpan;
 import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
@@ -46,17 +47,29 @@
     static final String TAG = "StaticLayout";
 
     /**
-     * Builder for static layouts. It would be better if this were a public
-     * API (as it would offer much greater flexibility for adding new options)
-     * but for the time being it's just internal.
-     *
-     * @hide
+     * Builder for static layouts. The builder is a newer pattern for constructing
+     * StaticLayout objects and should be preferred over the constructors,
+     * particularly to access newer features. To build a static layout, first
+     * call {@link #obtain} with the required arguments (text, paint, and width),
+     * then call setters for optional parameters, and finally {@link #build}
+     * to build the StaticLayout object. Parameters not explicitly set will get
+     * default values.
      */
     public final static class Builder {
         private Builder() {
             mNativePtr = nNewBuilder();
         }
 
+        /**
+         * Obtain a builder for constructing StaticLayout objects
+         *
+         * @param source The text to be laid out, optionally with spans
+         * @param start The index of the start of the text
+         * @param end The index + 1 of the end of the text
+         * @param paint The base paint used for layout
+         * @param width The width in pixels
+         * @return a builder object used for constructing the StaticLayout
+         */
         public static Builder obtain(CharSequence source, int start, int end, TextPaint paint,
                 int width) {
             Builder b = sPool.acquire();
@@ -100,6 +113,18 @@
             return setText(source, 0, source.length());
         }
 
+        /**
+         * Set the text. Only useful when re-using the builder, which is done for
+         * the internal implementation of {@link DynamicLayout} but not as part
+         * of normal {@link StaticLayout} usage.
+         *
+         * @param source The text to be laid out, optionally with spans
+         * @param start The index of the start of the text
+         * @param end The index + 1 of the end of the text
+         * @return this builder, useful for chaining
+         *
+         * @hide
+         */
         public Builder setText(CharSequence source, int start, int end) {
             mText = source;
             mStart = start;
@@ -107,11 +132,27 @@
             return this;
         }
 
+        /**
+         * Set the paint. Internal for reuse cases only.
+         *
+         * @param paint The base paint used for layout
+         * @return this builder, useful for chaining
+         *
+         * @hide
+         */
         public Builder setPaint(TextPaint paint) {
             mPaint = paint;
             return this;
         }
 
+        /**
+         * Set the width. Internal for reuse cases only.
+         *
+         * @param width The width in pixels
+         * @return this builder, useful for chaining
+         *
+         * @hide
+         */
         public Builder setWidth(int width) {
             mWidth = width;
             if (mEllipsize == null) {
@@ -120,53 +161,126 @@
             return this;
         }
 
+        /**
+         * Set the alignment. The default is {@link Layout.Alignment#ALIGN_NORMAL}.
+         *
+         * @param alignment Alignment for the resulting {@link StaticLayout}
+         * @return this builder, useful for chaining
+         */
         public Builder setAlignment(Alignment alignment) {
             mAlignment = alignment;
             return this;
         }
 
+        /**
+         * Set the text direction heuristic. The text direction heuristic is used to
+         * resolve text direction based per-paragraph based on the input text. The default is
+         * {@link TextDirectionHeuristics#FIRSTSTRONG_LTR}.
+         *
+         * @param textDir text direction heuristic for resolving BiDi behavior.
+         * @return this builder, useful for chaining
+         */
         public Builder setTextDir(TextDirectionHeuristic textDir) {
             mTextDir = textDir;
             return this;
         }
 
-        // TODO: combine the following, as they're almost always set together?
-        public Builder setSpacingMult(float spacingMult) {
+        /**
+         * Set line spacing parameters. The default is 0.0 for {@code spacingAdd}
+         * and 1.0 for {@code spacingMult}.
+         *
+         * @param spacingAdd line spacing add
+         * @param spacingMult line spacing multiplier
+         * @return this builder, useful for chaining
+         * @see android.widget.TextView#setLineSpacing
+         */
+        public Builder setLineSpacing(float spacingAdd, float spacingMult) {
+            mSpacingAdd = spacingAdd;
             mSpacingMult = spacingMult;
             return this;
         }
 
-        public Builder setSpacingAdd(float spacingAdd) {
-            mSpacingAdd = spacingAdd;
-            return this;
-        }
-
+        /**
+         * Set whether to include extra space beyond font ascent and descent (which is
+         * needed to avoid clipping in some languages, such as Arabic and Kannada). The
+         * default is {@code true}.
+         *
+         * @param includePad whether to include padding
+         * @return this builder, useful for chaining
+         * @see android.widget.TextView#setIncludeFontPadding
+         */
         public Builder setIncludePad(boolean includePad) {
             mIncludePad = includePad;
             return this;
         }
 
-        // TODO: combine the following?
+        /**
+         * Set the width as used for ellipsizing purposes, if it differs from the
+         * normal layout width. The default is the {@code width}
+         * passed to {@link #obtain}.
+         *
+         * @param ellipsizedWidth width used for ellipsizing, in pixels
+         * @return this builder, useful for chaining
+         * @see android.widget.TextView#setEllipsize
+         */
         public Builder setEllipsizedWidth(int ellipsizedWidth) {
             mEllipsizedWidth = ellipsizedWidth;
             return this;
         }
 
-        public Builder setEllipsize(TextUtils.TruncateAt ellipsize) {
+        /**
+         * Set ellipsizing on the layout. Causes words that are longer than the view
+         * is wide, or exceeding the number of lines (see #setMaxLines) in the case
+         * of {@link android.text.TextUtils.TruncateAt#END} or
+         * {@link android.text.TextUtils.TruncateAt#MARQUEE}, to be ellipsized instead
+         * of broken. The default is
+         * {@code null}, indicating no ellipsis is to be applied.
+         *
+         * @param ellipsize type of ellipsis behavior
+         * @return this builder, useful for chaining
+         * @see android.widget.TextView#setEllipsize
+         */
+        public Builder setEllipsize(@Nullable TextUtils.TruncateAt ellipsize) {
             mEllipsize = ellipsize;
             return this;
         }
 
+        /**
+         * Set maximum number of lines. This is particularly useful in the case of
+         * ellipsizing, where it changes the layout of the last line. The default is
+         * unlimited.
+         *
+         * @param maxLines maximum number of lines in the layout
+         * @return this builder, useful for chaining
+         * @see android.widget.TextView#setMaxLines
+         */
         public Builder setMaxLines(int maxLines) {
             mMaxLines = maxLines;
             return this;
         }
 
+        /**
+         * Set break strategy, useful for selecting high quality or balanced paragraph
+         * layout options. The default is {@link Layout#BREAK_STRATEGY_SIMPLE}.
+         *
+         * @param breakStrategy break strategy for paragraph layout
+         * @return this builder, useful for chaining
+         * @see android.widget.TextView#setBreakStrategy
+         */
         public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
             mBreakStrategy = breakStrategy;
             return this;
         }
 
+        /**
+         * Set indents. Arguments are arrays holding an indent amount, one per line, measured in
+         * pixels. For lines past the last element in the array, the last element repeats.
+         *
+         * @param leftIndents array of indent values for left margin, in pixels
+         * @param rightIndents array of indent values for right margin, in pixels
+         * @return this builder, useful for chaining
+         * @see android.widget.TextView#setIndents
+         */
         public Builder setIndents(int[] leftIndents, int[] rightIndents) {
             int leftLen = leftIndents == null ? 0 : leftIndents.length;
             int rightLen = rightIndents == null ? 0 : rightIndents.length;
@@ -220,6 +334,15 @@
             nAddReplacementRun(mNativePtr, start, end, width);
         }
 
+        /**
+         * Build the {@link StaticLayout} after options have been set.
+         *
+         * <p>Note: the builder object must not be reused in any way after calling this
+         * method. Setting parameters after calling this method, or calling it a second
+         * time on the same builder object, will likely lead to unexpected results.
+         *
+         * @return the newly constructed {@link StaticLayout} object
+         */
         public StaticLayout build() {
             StaticLayout result = new StaticLayout(this);
             Builder.recycle(this);
@@ -332,8 +455,7 @@
         Builder b = Builder.obtain(source, bufstart, bufend, paint, outerwidth)
             .setAlignment(align)
             .setTextDir(textDir)
-            .setSpacingMult(spacingmult)
-            .setSpacingAdd(spacingadd)
+            .setLineSpacing(spacingadd, spacingmult)
             .setIncludePad(includepad)
             .setEllipsizedWidth(ellipsizedWidth)
             .setEllipsize(ellipsize)