1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.widget;
18 
19 import android.content.Context;
20 import android.text.Editable;
21 import android.text.InputType;
22 import android.text.TextUtils;
23 import android.text.TextWatcher;
24 import android.util.AttributeSet;
25 import android.view.View;
26 import android.widget.EditText;
27 import android.widget.TextView;
28 
29 import androidx.annotation.VisibleForTesting;
30 import androidx.appcompat.app.AlertDialog;
31 import androidx.preference.PreferenceViewHolder;
32 
33 import com.android.settingslib.CustomEditTextPreferenceCompat;
34 
35 /**
36  * {@code EditTextPreference} that supports input validation.
37  */
38 public class ValidatedEditTextPreference extends CustomEditTextPreferenceCompat {
39 
40     public interface Validator {
isTextValid(String value)41         boolean isTextValid(String value);
42     }
43 
44     private final EditTextWatcher mTextWatcher = new EditTextWatcher();
45     private Validator mValidator;
46     private boolean mIsPassword;
47     private boolean mIsSummaryPassword;
48 
ValidatedEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)49     public ValidatedEditTextPreference(Context context, AttributeSet attrs,
50             int defStyleAttr, int defStyleRes) {
51         super(context, attrs, defStyleAttr, defStyleRes);
52     }
53 
ValidatedEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr)54     public ValidatedEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
55         super(context, attrs, defStyleAttr);
56     }
57 
ValidatedEditTextPreference(Context context, AttributeSet attrs)58     public ValidatedEditTextPreference(Context context, AttributeSet attrs) {
59         super(context, attrs);
60     }
61 
ValidatedEditTextPreference(Context context)62     public ValidatedEditTextPreference(Context context) {
63         super(context);
64     }
65 
66     @Override
onBindDialogView(View view)67     protected void onBindDialogView(View view) {
68         super.onBindDialogView(view);
69         final EditText editText = view.findViewById(android.R.id.edit);
70         if (editText != null && !TextUtils.isEmpty(editText.getText())) {
71             editText.setSelection(editText.getText().length());
72         }
73         if (mValidator != null && editText != null) {
74             editText.removeTextChangedListener(mTextWatcher);
75             if (mIsPassword) {
76                 editText.setInputType(
77                         InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
78                 editText.setMaxLines(1);
79             }
80             editText.addTextChangedListener(mTextWatcher);
81         }
82     }
83 
84     @Override
onBindViewHolder(PreferenceViewHolder holder)85     public void onBindViewHolder(PreferenceViewHolder holder) {
86         super.onBindViewHolder(holder);
87 
88         final TextView textView = (TextView) holder.findViewById(android.R.id.summary);
89         if (textView == null) {
90             return;
91         }
92         if (mIsSummaryPassword) {
93             textView.setInputType(
94                     InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
95         } else {
96             textView.setInputType(
97                     InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
98         }
99     }
100 
setIsPassword(boolean isPassword)101     public void setIsPassword(boolean isPassword) {
102         mIsPassword = isPassword;
103     }
104 
setIsSummaryPassword(boolean isPassword)105     public void setIsSummaryPassword(boolean isPassword) {
106         mIsSummaryPassword = isPassword;
107     }
108 
109     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
isPassword()110     public boolean isPassword() {
111         return mIsPassword;
112     }
113 
setValidator(Validator validator)114     public void setValidator(Validator validator) {
115         mValidator = validator;
116     }
117 
118     private class EditTextWatcher implements TextWatcher {
119         @Override
onTextChanged(CharSequence s, int start, int before, int count)120         public void onTextChanged(CharSequence s, int start, int before, int count) {
121         }
122 
123         @Override
beforeTextChanged(CharSequence s, int start, int before, int count)124         public void beforeTextChanged(CharSequence s, int start, int before, int count) {
125         }
126 
127         @Override
afterTextChanged(Editable s)128         public void afterTextChanged(Editable s) {
129             final EditText editText = getEditText();
130             if (mValidator != null && editText != null) {
131                 final AlertDialog dialog = (AlertDialog) getDialog();
132                 final boolean valid = mValidator.isTextValid(editText.getText().toString());
133                 dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(valid);
134             }
135         }
136     }
137 
138 }
139