I have a very simple question:
I have a EditTextPreference dialog which I want to use for getting the user's password and I want it to be masked.
How can I do that?
Here is a short example using xml:
<EditTextPreference android:key="@string/key" android:title="@string/title" android:summary="@string/summary" android:inputType="textPassword" /> Or you can use numberPassword instead of textPassword.
Preference that extends DialogPreference with custom Dialog.android:key="@string/key" stores it as plain text.For androidx library you should do it programmatically for example you could do it as follows, optionally I am setting the summary with asterisks according to the length of password:
[...] import android.os.Bundle; import android.text.InputType; import android.widget.EditText; import androidx.annotation.NonNull; import androidx.preference.EditTextPreference; import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceManager; import static androidx.preference.EditTextPreference.*; public class MySettingsFragment extends PreferenceFragmentCompat { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.preferences, rootKey); final EditTextPreference preference = findPreference("password"); if (preference != null) { preference.setSummaryProvider(new SummaryProvider() { @Override public CharSequence provideSummary(Preference preference) { String getPassword = PreferenceManager.getDefaultSharedPreferences(getContext()).getString("password", "not set"); //we assume getPassword is not null assert getPassword != null; //return "not set" else return password with asterisks if (getPassword.equals("not set")) { return getPassword; } else { return (setAsterisks(getPassword.length())); } } }); //set input type as password and set summary with asterisks the new password preference.setOnBindEditTextListener( new OnBindEditTextListener() { @Override public void onBindEditText(@NonNull final EditText editText) { editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); preference.setSummaryProvider(new SummaryProvider() { @Override public CharSequence provideSummary(Preference preference) { return setAsterisks(editText.getText().toString().length()); } }); } }); } } //return the password in asterisks private String setAsterisks(int length) { StringBuilder sb = new StringBuilder(); for (int s = 0; s < length; s++) { sb.append("*"); } return sb.toString(); } } In xml you should have something like:
<EditTextPreference android:dialogMessage="Enter your password" android:dialogTitle="Password" android:key="password" android:title="Password" /> For more info please look at developer.android
android:inputType="numberPassword" doesn't work for me. Eclipse told me, that no String values are allowed for this attribute. So i used following:
<EditTextPreference android:key="@string/key" android:title="@string/title" android:summary="@string/summary" android:inputType="number" android:password="true" /> This got me a EditTextPreference with a dotted textdisplay and a number keyboard for input.
For AndroidX Preferences, do:
password.setOnBindEditTextListener(editText -> { editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); }); The inputType XML attribute isn't used on androidx.
You can do it with the code below. HOWEVER, I still haven't figured out how to do the PASSWORD_TOGGLE thing. Doesn't work by just defining app:endIconMode="password_toggle" Can someone help with that?
The ANSWER: The "EditTextPreference" field "db_pwd" has the following defined:
android:inputType="textPassword" The latest Kotlin rev code:
class SettingsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(com.unified.helloworld.R.xml.my_preferences, rootKey) val pwdPref = findPreference<EditTextPreference>("db_pwd") if (pwdPref != null) { pwdPref.summaryProvider = SummaryProvider<Preference?> { val getPassword: String = PreferenceManager.getDefaultSharedPreferences(context) .getString("db_pwd", "Not set")!! // Return "Not set" else return password with asterisks if (getPassword == "Not set") { getPassword } else { setAsterisks(getPassword.length) } } // Set type as password and set summary with asterisks pwdPref.setOnBindEditTextListener( OnBindEditTextListener { editText -> editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD pwdPref.summaryProvider = SummaryProvider<Preference> { setAsterisks(editText.text.toString().length) } }) } } // Return the password in asterisks private fun setAsterisks(length: Int): String { val sb = java.lang.StringBuilder() for (s in 0 until length) { sb.append("*") } return sb.toString() } } If you want that the password mask persist also after device rotation is suffice to add the following imeOption:
in the edit text layout android:imeOptions="flagNoExtractUi"
or programmatically yourEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
EditTextPreference?