TextInputLayout.java revision 388841ca2f07d0da9bbdc66c51abe789e05cf17b
1c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes/*
2c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Copyright (C) 2015 The Android Open Source Project
3c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes *
4c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Licensed under the Apache License, Version 2.0 (the "License");
5c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * you may not use this file except in compliance with the License.
6c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * You may obtain a copy of the License at
7c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes *
8c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes *      http://www.apache.org/licenses/LICENSE-2.0
9c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes *
10c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * Unless required by applicable law or agreed to in writing, software
11c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * distributed under the License is distributed on an "AS IS" BASIS,
12c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * See the License for the specific language governing permissions and
14c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes * limitations under the License.
15c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes */
16c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
17c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banespackage android.support.design.widget;
18c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
19c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.content.Context;
20c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.content.res.ColorStateList;
21c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.content.res.TypedArray;
22c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.graphics.Canvas;
23c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.graphics.Color;
24c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.graphics.Paint;
25388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banesimport android.graphics.Typeface;
26c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.os.Handler;
27c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.os.Message;
28c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.support.design.R;
29c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.support.v4.view.AccessibilityDelegateCompat;
30c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.support.v4.view.ViewCompat;
31c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
32c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
33c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.text.Editable;
34c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.text.TextUtils;
35c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.text.TextWatcher;
36c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.util.AttributeSet;
37c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.util.TypedValue;
38c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.view.Gravity;
39c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.view.View;
40c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.view.ViewGroup;
41c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.view.accessibility.AccessibilityEvent;
42c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.view.animation.AccelerateInterpolator;
43c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.widget.EditText;
44c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.widget.LinearLayout;
45c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banesimport android.widget.TextView;
46c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
47c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes/**
489fb154338a62edc2c57dc036895199d6f1769400Chris Banes * Layout which wraps an {@link android.widget.EditText} (or descendant) to show a floating label
499fb154338a62edc2c57dc036895199d6f1769400Chris Banes * when the hint is hidden due to the user inputting text.
509fb154338a62edc2c57dc036895199d6f1769400Chris Banes *
519fb154338a62edc2c57dc036895199d6f1769400Chris Banes * Also supports showing an error via {@link #setErrorEnabled(boolean)} and
529fb154338a62edc2c57dc036895199d6f1769400Chris Banes * {@link #setError(CharSequence)}.
53c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes */
54c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banespublic class TextInputLayout extends LinearLayout {
55c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
56f44e88b81821e61a65886cc7027617ca8995070bChris Banes    private static final int ANIMATION_DURATION = 200;
57c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private static final int MSG_UPDATE_LABEL = 0;
58c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
59c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private EditText mEditText;
60c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private CharSequence mHint;
61c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
62c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private boolean mErrorEnabled;
63c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private TextView mErrorView;
64c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private int mErrorTextAppearance;
65c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
66c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private ColorStateList mLabelTextColor;
67c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
68c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private final CollapsingTextHelper mCollapsingTextHelper;
69c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private final Handler mHandler;
70c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
71f44e88b81821e61a65886cc7027617ca8995070bChris Banes    private ValueAnimatorCompat mAnimator;
72f44e88b81821e61a65886cc7027617ca8995070bChris Banes
73c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    public TextInputLayout(Context context) {
74c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        this(context, null);
75c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
76c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
77c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    public TextInputLayout(Context context, AttributeSet attrs) {
7844dc3d86d8fa6544d49b2e14f89c9b1f49639dbdChris Banes        super(context, attrs);
79c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
80c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        setOrientation(VERTICAL);
81c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        setWillNotDraw(false);
82c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
83c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper = new CollapsingTextHelper(this);
84c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mHandler = new Handler(new Handler.Callback() {
85c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            @Override
86c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            public boolean handleMessage(Message message) {
87c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                switch (message.what) {
88c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    case MSG_UPDATE_LABEL:
89c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                        updateLabelVisibility(true);
90c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                        return true;
91c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                }
92c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                return false;
93c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
94c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        });
95c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
96c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.setTextSizeInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
97c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.setPositionInterpolator(new AccelerateInterpolator());
98c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.setCollapsedTextVerticalGravity(Gravity.TOP);
99c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
100c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        final TypedArray a = context.obtainStyledAttributes(attrs,
10144dc3d86d8fa6544d49b2e14f89c9b1f49639dbdChris Banes                R.styleable.TextInputLayout, 0, R.style.Widget_Design_TextInputLayout);
102c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mHint = a.getText(R.styleable.TextInputLayout_android_hint);
103c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
104c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        final int hintAppearance = a.getResourceId(
105c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                R.styleable.TextInputLayout_hintTextAppearance, -1);
106c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (hintAppearance != -1) {
107c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            mCollapsingTextHelper.setCollapsedTextAppearance(hintAppearance);
108c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
109c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
110c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mErrorTextAppearance = a.getResourceId(R.styleable.TextInputLayout_errorTextAppearance, 0);
111c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        final boolean errorEnabled = a.getBoolean(R.styleable.TextInputLayout_errorEnabled, false);
112c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
113c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // We create a ColorStateList using the specified text color, combining it with our
114c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // theme's textColorHint
115c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mLabelTextColor = createLabelTextColorStateList(
116c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                mCollapsingTextHelper.getCollapsedTextColor());
117c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
118c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.setCollapsedTextColor(mLabelTextColor.getDefaultColor());
119c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.setExpandedTextColor(mLabelTextColor.getDefaultColor());
120c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
121c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        a.recycle();
122c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
123c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (errorEnabled) {
124c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            setErrorEnabled(true);
125c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
126c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
127c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (ViewCompat.getImportantForAccessibility(this)
128c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
129c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            // Make sure we're important for accessibility if we haven't been explicitly not
130c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            ViewCompat.setImportantForAccessibility(this,
131c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
132c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
133c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
134c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        ViewCompat.setAccessibilityDelegate(this, new TextInputAccessibilityDelegate());
135c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
136c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
137c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    @Override
138c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    public void addView(View child, int index, ViewGroup.LayoutParams params) {
139c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (child instanceof EditText) {
140c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            params = setEditText((EditText) child, params);
141c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            super.addView(child, 0, params);
142c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        } else {
143c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            // Carry on adding the View...
144c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            super.addView(child, index, params);
145c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
146c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
147c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
148388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes    /**
149388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes     * Set the typeface to use for the both the expanded and floating hint.
150388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes     *
151388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes     * @param typeface typeface to use, or {@code null} to use the default.
152388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes     */
153388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes    public void setTypeface(Typeface typeface) {
154388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes        mCollapsingTextHelper.setTypeface(typeface);
155388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes    }
156388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes
157c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private LayoutParams setEditText(EditText editText, ViewGroup.LayoutParams lp) {
158c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // If we already have an EditText, throw an exception
159c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (mEditText != null) {
160c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            throw new IllegalArgumentException("We already have an EditText, can only have one");
161c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
162c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mEditText = editText;
163c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
164388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes        // Use the EditText's typeface, and it's text size for our expanded text
165388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes        mCollapsingTextHelper.setTypeface(mEditText.getTypeface());
166c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.setExpandedTextSize(mEditText.getTextSize());
167c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
168c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // Add a TextWatcher so that we know when the text input has changed
169c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mEditText.addTextChangedListener(new TextWatcher() {
170c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            @Override
171c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            public void afterTextChanged(Editable s) {
172c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                mHandler.sendEmptyMessage(MSG_UPDATE_LABEL);
173c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
174c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
175c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            @Override
176c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
177c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
178c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
179c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            @Override
180c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            public void onTextChanged(CharSequence s, int start, int before, int count) {
181c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
182c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        });
183c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
184c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // Add focus listener to the EditText so that we can notify the label that it is activated.
185c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // Allows the use of a ColorStateList for the text color on the label
186c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
187c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            @Override
188c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            public void onFocusChange(View view, boolean focused) {
189c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                mHandler.sendEmptyMessage(MSG_UPDATE_LABEL);
190c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
191c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        });
192c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
193c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // If we do not have a valid hint, try and retrieve it from the EditText
194c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (TextUtils.isEmpty(mHint)) {
195c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            setHint(mEditText.getHint());
196c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            // Clear the EditText's hint as we will display it ourselves
197c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            mEditText.setHint(null);
198c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
199c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
200c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (mErrorView != null) {
201c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            // Add some start/end padding to the error so that it matches the EditText
202c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            ViewCompat.setPaddingRelative(mErrorView, ViewCompat.getPaddingStart(mEditText),
203c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom());
204c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
205c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
206c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // Update the label visibility with no animation
207c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        updateLabelVisibility(false);
208c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
209c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // Create a new FrameLayout.LayoutParams so that we can add enough top margin
210c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // to the EditText so make room for the label
211c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        LayoutParams newLp = new LayoutParams(lp);
212c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        Paint paint = new Paint();
213388841ca2f07d0da9bbdc66c51abe789e05cf17bChris Banes        paint.setTypeface(mCollapsingTextHelper.getTypeface());
214c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        paint.setTextSize(mCollapsingTextHelper.getExpandedTextSize());
215c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        newLp.topMargin = (int) -paint.ascent();
216c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
217c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        return newLp;
218c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
219c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
220c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private void updateLabelVisibility(boolean animate) {
221c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        boolean hasText = !TextUtils.isEmpty(mEditText.getText());
222c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        boolean isFocused = mEditText.isFocused();
223c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
224c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.setCollapsedTextColor(mLabelTextColor.getColorForState(
225c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                isFocused ? FOCUSED_STATE_SET : EMPTY_STATE_SET,
226c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                mLabelTextColor.getDefaultColor()));
227c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
228c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (hasText || isFocused) {
229c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            // We should be showing the label so do so if it isn't already
230c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            collapseHint(animate);
231c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        } else {
232c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            // We should not be showing the label so hide it
233c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            expandHint(animate);
234c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
235c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
236c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
237c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    /**
238c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * @return the {@link android.widget.EditText} text input
239c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     */
240c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    public EditText getEditText() {
241c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        return mEditText;
242c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
243c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
244c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    /**
245c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * Set the hint to be displayed in the floating label
246c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     */
247c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    public void setHint(CharSequence hint) {
248c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mHint = hint;
249c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.setText(hint);
250c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
251c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
252c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
253c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
254c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    /**
255c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * Whether the error functionality is enabled or not in this layout. Enabling this
256c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * functionality before setting an error message via {@link #setError(CharSequence)}, will mean
257c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * that this layout will not change size when an error is displayed.
258c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     */
259c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    public void setErrorEnabled(boolean enabled) {
260c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (mErrorEnabled != enabled) {
261c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            if (enabled) {
262c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                mErrorView = new TextView(getContext());
263c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                mErrorView.setTextAppearance(getContext(), mErrorTextAppearance);
264c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                mErrorView.setVisibility(INVISIBLE);
265c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                addView(mErrorView);
266c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
267c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                if (mEditText != null) {
268c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    // Add some start/end padding to the error so that it matches the EditText
269c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    ViewCompat.setPaddingRelative(mErrorView, ViewCompat.getPaddingStart(mEditText),
270c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                            0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom());
271c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                }
272c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            } else {
273c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                removeView(mErrorView);
274c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                mErrorView = null;
275c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
276c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            mErrorEnabled = enabled;
277c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
278c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
279c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
280c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    /**
281c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * Sets an error message that will be displayed below our {@link EditText}. If the
282c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * {@code error} is {@code null}, the error message will be cleared.
283c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * <p>
284c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * If the error functionality has not been enabled via {@link #setErrorEnabled(boolean)}, then
285c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * it will be automatically enabled if {@code error} is not empty.
286c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     *
287c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     * @param error Error message to display, or null to clear
288c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes     */
289c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    public void setError(CharSequence error) {
290c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (!mErrorEnabled) {
291c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            if (TextUtils.isEmpty(error)) {
292c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                // If error isn't enabled, and the error is empty, just return
293c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                return;
294c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
295c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            // Else, we'll assume that they want to enable the error functionality
296c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            setErrorEnabled(true);
297c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
298c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
299c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (!TextUtils.isEmpty(error)) {
300c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            mErrorView.setText(error);
301c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            mErrorView.setVisibility(VISIBLE);
302c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            ViewCompat.setAlpha(mErrorView, 0f);
303c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            ViewCompat.animate(mErrorView)
304c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    .alpha(1f)
305c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    .setDuration(ANIMATION_DURATION)
306c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
307c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    .setListener(null)
308c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    .start();
309c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        } else {
310c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            if (mErrorView.getVisibility() == VISIBLE) {
311c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                ViewCompat.animate(mErrorView)
312c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                        .alpha(0f)
313c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                        .setDuration(ANIMATION_DURATION)
314c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                        .setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR)
315c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                        .setListener(new ViewPropertyAnimatorListenerAdapter() {
316c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                            @Override
317c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                            public void onAnimationEnd(View view) {
318c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                                mErrorView.setText(null);
319c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                                mErrorView.setVisibility(INVISIBLE);
320c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                            }
321c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                        }).start();
322c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
323c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
324c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
325c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
326c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
327c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
328c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    @Override
329c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    public void draw(Canvas canvas) {
330c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        super.draw(canvas);
331c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.draw(canvas);
332c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
333c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
334c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    @Override
335c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
336c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        super.onLayout(changed, left, top, right, bottom);
337c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
338c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        mCollapsingTextHelper.onLayout(changed, left, top, right, bottom);
339c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
340c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (mEditText != null) {
341a611711d69eaf8ba65af12118a96810fc17b4163Chris Banes            final int l = mEditText.getLeft() + mEditText.getCompoundPaddingLeft();
342a611711d69eaf8ba65af12118a96810fc17b4163Chris Banes            final int r = mEditText.getRight() - mEditText.getCompoundPaddingRight();
343c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
344c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            mCollapsingTextHelper.setExpandedBounds(l,
345a611711d69eaf8ba65af12118a96810fc17b4163Chris Banes                    mEditText.getTop() + mEditText.getCompoundPaddingTop(),
346a611711d69eaf8ba65af12118a96810fc17b4163Chris Banes                    r, mEditText.getBottom() - mEditText.getCompoundPaddingBottom());
347c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
348c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            // Set the collapsed bounds to be the the full height (minus padding) to match the
349c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            // EditText's editable area
350c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            mCollapsingTextHelper.setCollapsedBounds(l, getPaddingTop(),
351c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                    r, bottom - top - getPaddingBottom());
352c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
353c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
354c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
355c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private void collapseHint(boolean animate) {
356c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (animate) {
357c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            animateToExpansionFraction(1f);
358c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        } else {
359c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            mCollapsingTextHelper.setExpansionFraction(1f);
360c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
361c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
362c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
363c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private void expandHint(boolean animate) {
364c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (animate) {
365c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            animateToExpansionFraction(0f);
366c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        } else {
367c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            mCollapsingTextHelper.setExpansionFraction(0f);
368c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
369c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
370c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
371c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private void animateToExpansionFraction(final float target) {
372f44e88b81821e61a65886cc7027617ca8995070bChris Banes        if (mAnimator == null) {
373f44e88b81821e61a65886cc7027617ca8995070bChris Banes            mAnimator = ViewUtils.createAnimator();
374f44e88b81821e61a65886cc7027617ca8995070bChris Banes            mAnimator.setInterpolator(AnimationUtils.LINEAR_INTERPOLATOR);
375f44e88b81821e61a65886cc7027617ca8995070bChris Banes            mAnimator.setDuration(ANIMATION_DURATION);
376f44e88b81821e61a65886cc7027617ca8995070bChris Banes            mAnimator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() {
377f44e88b81821e61a65886cc7027617ca8995070bChris Banes                @Override
378f44e88b81821e61a65886cc7027617ca8995070bChris Banes                public void onAnimationUpdate(ValueAnimatorCompat animator) {
379f44e88b81821e61a65886cc7027617ca8995070bChris Banes                    mCollapsingTextHelper.setExpansionFraction(animator.getAnimatedFloatValue());
380f44e88b81821e61a65886cc7027617ca8995070bChris Banes                }
381f44e88b81821e61a65886cc7027617ca8995070bChris Banes            });
382f44e88b81821e61a65886cc7027617ca8995070bChris Banes        } else if (mAnimator.isRunning()) {
383f44e88b81821e61a65886cc7027617ca8995070bChris Banes            mAnimator.cancel();
384f44e88b81821e61a65886cc7027617ca8995070bChris Banes        }
385c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
386f44e88b81821e61a65886cc7027617ca8995070bChris Banes        mAnimator.setFloatValues(mCollapsingTextHelper.getExpansionFraction(), target);
387f44e88b81821e61a65886cc7027617ca8995070bChris Banes        mAnimator.start();
388c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
389c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
390c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private ColorStateList createLabelTextColorStateList(int color) {
391c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        final int[][] states = new int[2][];
392c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        final int[] colors = new int[2];
393c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        int i = 0;
394c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
395c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        // Focused
396c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        states[i] = FOCUSED_STATE_SET;
397c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        colors[i] = color;
398c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        i++;
399c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
400c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        states[i] = EMPTY_STATE_SET;
401c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        colors[i] = getThemeAttrColor(android.R.attr.textColorHint);
402c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        i++;
403c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
404c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        return new ColorStateList(states, colors);
405c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
406c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
407c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private int getThemeAttrColor(int attr) {
408c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        TypedValue tv = new TypedValue();
409c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        if (getContext().getTheme().resolveAttribute(attr, tv, true)) {
410c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            return tv.data;
411c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        } else {
412c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            return Color.MAGENTA;
413c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
414c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
415c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
416c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    private class TextInputAccessibilityDelegate extends AccessibilityDelegateCompat {
417c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        @Override
418c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
419c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            super.onInitializeAccessibilityEvent(host, event);
420c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            event.setClassName(TextInputLayout.class.getSimpleName());
421c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
422c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
423c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        @Override
424c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
425c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            super.onPopulateAccessibilityEvent(host, event);
426c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
427c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            final CharSequence text = mCollapsingTextHelper.getText();
428c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            if (!TextUtils.isEmpty(text)) {
429c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                event.getText().add(text);
430c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
431c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
432c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
433c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        @Override
434c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
435c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            super.onInitializeAccessibilityNodeInfo(host, info);
436c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            info.setClassName(TextInputLayout.class.getSimpleName());
437c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes
438c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            final CharSequence text = mCollapsingTextHelper.getText();
439c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            if (!TextUtils.isEmpty(text)) {
440c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                info.setText(text);
441c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
442c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            if (mEditText != null) {
443c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                info.setLabelFor(mEditText);
444c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
445c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            final CharSequence error = mErrorView != null ? mErrorView.getText() : null;
446c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            if (!TextUtils.isEmpty(error)) {
447c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                info.setContentInvalid(true);
448c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes                info.setError(error);
449c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes            }
450c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes        }
451c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes    }
452c5b63021dfda1dd155775a0b4845c5ca3c70b1b0Chris Banes}