Hint visibility in AppCompat text widgets in landscape mode

Make the logic from TextInputEditText generic so that the
hint is visible in landscape mode on all AppCompat text
widgets.

Test: manual inspection in demo app
Bug: 65885462
Bug: 63996608
Bug: 37115286
Change-Id: Idde0f15f82b72398112ff56df19d5c778d330ec8
diff --git a/design/src/android/support/design/widget/TextInputEditText.java b/design/src/android/support/design/widget/TextInputEditText.java
index 7235ec2..ee6c32c 100644
--- a/design/src/android/support/design/widget/TextInputEditText.java
+++ b/design/src/android/support/design/widget/TextInputEditText.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.support.v7.widget.AppCompatEditText;
+import android.support.v7.widget.WithHint;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewParent;
@@ -48,12 +49,12 @@
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
         final InputConnection ic = super.onCreateInputConnection(outAttrs);
         if (ic != null && outAttrs.hintText == null) {
-            // If we don't have a hint and our parent is a TextInputLayout, use it's hint for the
+            // If we don't have a hint and our parent implements WithHint, use its hint for the
             // EditorInfo. This allows us to display a hint in 'extract mode'.
             ViewParent parent = getParent();
             while (parent instanceof View) {
-                if (parent instanceof TextInputLayout) {
-                    outAttrs.hintText = ((TextInputLayout) parent).getHint();
+                if (parent instanceof WithHint) {
+                    outAttrs.hintText = ((WithHint) parent).getHint();
                     break;
                 }
                 parent = parent.getParent();
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
index c9e8010..2ed79e4 100644
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ b/design/src/android/support/design/widget/TextInputLayout.java
@@ -53,6 +53,7 @@
 import android.support.v7.widget.AppCompatDrawableManager;
 import android.support.v7.widget.AppCompatTextView;
 import android.support.v7.widget.TintTypedArray;
+import android.support.v7.widget.WithHint;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
@@ -113,7 +114,7 @@
  * may not return the TextInputLayout itself, but rather an intermediate View. If you need
  * to access a View directly, set an {@code android:id} and use {@link View#findViewById(int)}.
  */
-public class TextInputLayout extends LinearLayout {
+public class TextInputLayout extends LinearLayout implements WithHint {
 
     private static final int ANIMATION_DURATION = 200;
     private static final int INVALID_MAX_LENGTH = -1;
@@ -497,6 +498,7 @@
      *
      * @attr ref android.support.design.R.styleable#TextInputLayout_android_hint
      */
+    @Override
     @Nullable
     public CharSequence getHint() {
         return mHintEnabled ? mHint : null;
diff --git a/samples/SupportDesignDemos/src/main/res/layout/design_text_input.xml b/samples/SupportDesignDemos/src/main/res/layout/design_text_input.xml
index 6dbbb92..fc9ff00 100644
--- a/samples/SupportDesignDemos/src/main/res/layout/design_text_input.xml
+++ b/samples/SupportDesignDemos/src/main/res/layout/design_text_input.xml
@@ -96,6 +96,22 @@
         </android.support.design.widget.TextInputLayout>
 
         <android.support.design.widget.TextInputLayout
+            android:id="@+id/input_auto_complete"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            app:counterEnabled="true"
+            app:counterMaxLength="30">
+
+            <AutoCompleteTextView
+                android:id="@+id/edit_auto_complete"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="@string/form_auto_complete" />
+
+        </android.support.design.widget.TextInputLayout>
+
+        <android.support.design.widget.TextInputLayout
             android:id="@+id/input_password"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/samples/SupportDesignDemos/src/main/res/values/strings.xml b/samples/SupportDesignDemos/src/main/res/values/strings.xml
index 74630d9..6ebe24c 100644
--- a/samples/SupportDesignDemos/src/main/res/values/strings.xml
+++ b/samples/SupportDesignDemos/src/main/res/values/strings.xml
@@ -69,6 +69,7 @@
     <string name="form_username">Username</string>
     <string name="form_email">Email address</string>
     <string name="form_description">Description</string>
+    <string name="form_auto_complete">Auto complete</string>
     <string name="form_password">Password field</string>
     <string name="show_error">Show error</string>
     <string name="toggle_enabled">Toggle enabled</string>
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatAutoCompleteTextView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatAutoCompleteTextView.java
index 5b0a2f8..e41bec7 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatAutoCompleteTextView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatAutoCompleteTextView.java
@@ -29,6 +29,8 @@
 import android.support.v7.appcompat.R;
 import android.support.v7.content.res.AppCompatResources;
 import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
 import android.widget.AutoCompleteTextView;
 
 /**
@@ -177,4 +179,10 @@
             mTextHelper.onSetTextAppearance(context, resId);
         }
     }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        return AppCompatHintHelper.onCreateInputConnection(super.onCreateInputConnection(outAttrs),
+                outAttrs, this);
+    }
 }
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCheckedTextView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCheckedTextView.java
index 921f0a2..dca409c 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCheckedTextView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatCheckedTextView.java
@@ -20,6 +20,8 @@
 import android.support.annotation.DrawableRes;
 import android.support.v7.content.res.AppCompatResources;
 import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
 import android.widget.CheckedTextView;
 
 /**
@@ -79,4 +81,10 @@
             mTextHelper.applyCompoundDrawablesTints();
         }
     }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        return AppCompatHintHelper.onCreateInputConnection(super.onCreateInputConnection(outAttrs),
+                outAttrs, this);
+    }
 }
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java
index 406e364..6831fcb 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java
@@ -28,6 +28,8 @@
 import android.support.v4.view.TintableBackgroundView;
 import android.support.v7.appcompat.R;
 import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
 import android.widget.EditText;
 
 /**
@@ -159,4 +161,10 @@
             mTextHelper.onSetTextAppearance(context, resId);
         }
     }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        return AppCompatHintHelper.onCreateInputConnection(super.onCreateInputConnection(outAttrs),
+                outAttrs, this);
+    }
 }
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatHintHelper.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatHintHelper.java
new file mode 100644
index 0000000..0d30fb7
--- /dev/null
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatHintHelper.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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.
+ */
+
+package android.support.v7.widget;
+
+import android.view.View;
+import android.view.ViewParent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+class AppCompatHintHelper {
+
+    static InputConnection onCreateInputConnection(InputConnection ic, EditorInfo outAttrs,
+            View view) {
+        if (ic != null && outAttrs.hintText == null) {
+            // If we don't have a hint and the parent implements WithHint, use its hint for the
+            // EditorInfo. This allows us to display a hint in 'extract mode'.
+            ViewParent parent = view.getParent();
+            while (parent instanceof View) {
+                if (parent instanceof WithHint) {
+                    outAttrs.hintText = ((WithHint) parent).getHint();
+                    break;
+                }
+                parent = parent.getParent();
+            }
+        }
+        return ic;
+    }
+
+}
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
index 8060d7d..b71b08a 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatMultiAutoCompleteTextView.java
@@ -29,6 +29,8 @@
 import android.support.v7.appcompat.R;
 import android.support.v7.content.res.AppCompatResources;
 import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
 import android.widget.MultiAutoCompleteTextView;
 
 /**
@@ -177,4 +179,10 @@
             mTextHelper.onSetTextAppearance(context, resId);
         }
     }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        return AppCompatHintHelper.onCreateInputConnection(super.onCreateInputConnection(outAttrs),
+                outAttrs, this);
+    }
 }
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextView.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextView.java
index cfa6a2a..d813277 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatTextView.java
@@ -31,6 +31,8 @@
 import android.support.v4.widget.TextViewCompat;
 import android.support.v7.appcompat.R;
 import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
 import android.widget.TextView;
 
 /**
@@ -361,4 +363,10 @@
         }
         return new int[0];
     }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        return AppCompatHintHelper.onCreateInputConnection(super.onCreateInputConnection(outAttrs),
+                outAttrs, this);
+    }
 }
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/WithHint.java b/v7/appcompat/src/main/java/android/support/v7/widget/WithHint.java
new file mode 100644
index 0000000..d14f483
--- /dev/null
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/WithHint.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public interface WithHint {
+    /**
+     * 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.
+     */
+    @Nullable
+    CharSequence getHint();
+}