Add setHintEnabled to TextInputLayout

BUG: 24800082

Change-Id: Idc8713a8e4516a8d93a08f151d9efbd083f29bc9
diff --git a/design/api/current.txt b/design/api/current.txt
index a1d9fab..9336032 100644
--- a/design/api/current.txt
+++ b/design/api/current.txt
@@ -431,12 +431,14 @@
     method public boolean isCounterEnabled();
     method public boolean isErrorEnabled();
     method public boolean isHintAnimationEnabled();
+    method public boolean isHintEnabled();
     method public void setCounterEnabled(boolean);
     method public void setCounterMaxLength(int);
     method public void setError(java.lang.CharSequence);
     method public void setErrorEnabled(boolean);
     method public void setHint(java.lang.CharSequence);
     method public void setHintAnimationEnabled(boolean);
+    method public void setHintEnabled(boolean);
     method public void setHintTextAppearance(int);
     method public void setTypeface(android.graphics.Typeface);
   }
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
index 0179ec7..3079180 100644
--- a/design/res/values/attrs.xml
+++ b/design/res/values/attrs.xml
@@ -162,6 +162,8 @@
         <attr name="hintTextAppearance" format="reference"/>
         <!-- The hint to display in the floating label -->
         <attr name="android:hint"/>
+        <!-- Whether the layout's floating label functionality is enabled -->
+        <attr name="hintEnabled" format="boolean"/>
         <!-- Whether the layout is laid out as if an error will be displayed -->
         <attr name="errorEnabled" format="boolean"/>
         <!-- TextAppearance of any error message displayed -->
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index 402878c..162643e 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -61,6 +61,8 @@
     private static final int INVALID_MAX_LENGTH = -1;
 
     private EditText mEditText;
+
+    private boolean mHintEnabled;
     private CharSequence mHint;
 
     private Paint mTmpPaint;
@@ -111,6 +113,7 @@
 
         final TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.TextInputLayout, defStyleAttr, R.style.Widget_Design_TextInputLayout);
+        mHintEnabled = a.getBoolean(R.styleable.TextInputLayout_hintEnabled, true);
         setHint(a.getText(R.styleable.TextInputLayout_android_hint));
         mHintAnimationEnabled = a.getBoolean(
                 R.styleable.TextInputLayout_hintAnimationEnabled, true);
@@ -198,7 +201,7 @@
         mEditText.addTextChangedListener(new TextWatcher() {
             @Override
             public void afterTextChanged(Editable s) {
-                updateLabelVisibility(true);
+                updateLabelState(true);
                 if (mCounterEnabled) {
                     updateCounter(s.length());
                 }
@@ -216,8 +219,8 @@
             mDefaultTextColor = mEditText.getHintTextColors();
         }
 
-        // If we do not have a valid hint, try and retrieve it from the EditText
-        if (TextUtils.isEmpty(mHint)) {
+        // If we do not have a valid hint, try and retrieve it from the EditText, if enabled
+        if (mHintEnabled && TextUtils.isEmpty(mHint)) {
             setHint(mEditText.getHint());
             // Clear the EditText's hint as we will display it ourselves
             mEditText.setHint(null);
@@ -232,7 +235,7 @@
         }
 
         // Update the label visibility with no animation
-        updateLabelVisibility(false);
+        updateLabelState(false);
     }
 
     private LayoutParams updateEditTextMargin(ViewGroup.LayoutParams lp) {
@@ -240,17 +243,21 @@
         // to the EditText so make room for the label
         LayoutParams llp = lp instanceof LayoutParams ? (LayoutParams) lp : new LayoutParams(lp);
 
-        if (mTmpPaint == null) {
-            mTmpPaint = new Paint();
+        if (mHintEnabled) {
+            if (mTmpPaint == null) {
+                mTmpPaint = new Paint();
+            }
+            mTmpPaint.setTypeface(mCollapsingTextHelper.getCollapsedTypeface());
+            mTmpPaint.setTextSize(mCollapsingTextHelper.getCollapsedTextSize());
+            llp.topMargin = (int) -mTmpPaint.ascent();
+        } else {
+            llp.topMargin = 0;
         }
-        mTmpPaint.setTypeface(mCollapsingTextHelper.getCollapsedTypeface());
-        mTmpPaint.setTextSize(mCollapsingTextHelper.getCollapsedTextSize());
-        llp.topMargin = (int) -mTmpPaint.ascent();
 
         return llp;
     }
 
-    private void updateLabelVisibility(boolean animate) {
+    private void updateLabelState(boolean animate) {
         final boolean hasText = mEditText != null && !TextUtils.isEmpty(mEditText.getText());
         final boolean isFocused = arrayContains(getDrawableState(), android.R.attr.state_focused);
         final boolean isErrorShowing = !TextUtils.isEmpty(getError());
@@ -287,25 +294,89 @@
     }
 
     /**
-     * Set the hint to be displayed in the floating label
+     * Set the hint to be displayed in the floating label, if enabled.
+     *
+     * @see #setHintEnabled(boolean)
      *
      * @attr ref android.support.design.R.styleable#TextInputLayout_android_hint
      */
     public void setHint(@Nullable CharSequence hint) {
+        if (mHintEnabled) {
+            setHintInternal(hint);
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        }
+    }
+
+    private void setHintInternal(CharSequence hint) {
         mHint = hint;
         mCollapsingTextHelper.setText(hint);
-
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
     }
 
     /**
-     * Returns the hint which is displayed in the floating label.
+     * Returns the hint which is displayed in the floating label, if enabled.
+     *
+     * @return the hint, or null if there isn't one set, or the hint is not enabled.
      *
      * @attr ref android.support.design.R.styleable#TextInputLayout_android_hint
      */
     @Nullable
     public CharSequence getHint() {
-        return mHint;
+        return mHintEnabled ? mHint : null;
+    }
+
+    /**
+     * Sets whether the floating label functionality is enabled or not in this layout.
+     *
+     * <p>If enabled, any non-empty hint in the child EditText will be moved into the floating
+     * hint, and its existing hint will be cleared. If disabled, then any non-empty floating hint
+     * in this layout will be moved into the EditText, and this layout's hint will be cleared.</p>
+     *
+     * @see #setHint(CharSequence)
+     * @see #isHintEnabled()
+     *
+     * @attr ref android.support.design.R.styleable#TextInputLayout_hintEnabled
+     */
+    public void setHintEnabled(boolean enabled) {
+        if (enabled != mHintEnabled) {
+            mHintEnabled = enabled;
+
+            final CharSequence editTextHint = mEditText.getHint();
+            if (!mHintEnabled) {
+                if (!TextUtils.isEmpty(mHint) && TextUtils.isEmpty(editTextHint)) {
+                    // If the hint is disabled, but we have a hint set, and the EditText doesn't,
+                    // pass it through...
+                    mEditText.setHint(mHint);
+                }
+                // Now clear out any set hint
+                setHintInternal(null);
+            } else {
+                if (!TextUtils.isEmpty(editTextHint)) {
+                    // If the hint is now enabled and the EditText has one set, we'll use it if
+                    // we don't already have one, and clear the EditText's
+                    if (TextUtils.isEmpty(mHint)) {
+                        setHint(editTextHint);
+                    }
+                    mEditText.setHint(null);
+                }
+            }
+
+            // Now update the EditText top margin
+            if (mEditText != null) {
+                final LayoutParams lp = updateEditTextMargin(mEditText.getLayoutParams());
+                mEditText.setLayoutParams(lp);
+            }
+        }
+    }
+
+    /**
+     * Returns whether the floating label functionality is enabled or not in this layout.
+     *
+     * @see #setHintEnabled(boolean)
+     *
+     * @attr ref android.support.design.R.styleable#TextInputLayout_hintEnabled
+     */
+    public boolean isHintEnabled() {
+        return mHintEnabled;
     }
 
     /**
@@ -318,7 +389,7 @@
         mFocusedTextColor = ColorStateList.valueOf(mCollapsingTextHelper.getCollapsedTextColor());
 
         if (mEditText != null) {
-            updateLabelVisibility(false);
+            updateLabelState(false);
 
             // Text size might have changed so update the top margin
             LayoutParams lp = updateEditTextMargin(mEditText.getLayoutParams());
@@ -442,7 +513,7 @@
             // Set the EditText's background tint to the error color
             mErrorShown = true;
             updateEditTextBackground();
-            updateLabelVisibility(true);
+            updateLabelState(true);
         } else {
             if (mErrorView.getVisibility() == VISIBLE) {
                 ViewCompat.animate(mErrorView)
@@ -454,7 +525,7 @@
                             public void onAnimationEnd(View view) {
                                 view.setVisibility(INVISIBLE);
 
-                                updateLabelVisibility(true);
+                                updateLabelState(true);
                             }
                         }).start();
 
@@ -547,7 +618,7 @@
                     length, mCounterMaxLength));
         }
         if (mEditText != null && wasCounterOverflowed != mCounterOverflowed) {
-            updateLabelVisibility(false);
+            updateLabelState(false);
             updateEditTextBackground();
         }
     }
@@ -609,14 +680,17 @@
     @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
-        mCollapsingTextHelper.draw(canvas);
+
+        if (mHintEnabled) {
+            mCollapsingTextHelper.draw(canvas);
+        }
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
-        if (mEditText != null) {
+        if (mHintEnabled && mEditText != null) {
             final int l = mEditText.getLeft() + mEditText.getCompoundPaddingLeft();
             final int r = mEditText.getRight() - mEditText.getCompoundPaddingRight();
 
@@ -637,7 +711,7 @@
     public void refreshDrawableState() {
         super.refreshDrawableState();
         // Drawable state has changed so see if we need to update the label
-        updateLabelVisibility(ViewCompat.isLaidOut(this));
+        updateLabelState(ViewCompat.isLaidOut(this));
     }
 
     private void collapseHint(boolean animate) {