For security needs I'm using the char array version of setText
to avoid using String
version.
public final void setText (char[] text,
int start,
int len)
BindingAdapter :
public class DataBindingAdapter {
@BindingAdapter("android:text")
public static void setCharArray(ClearableEditText view, char[] value) {
if(value == null) return;
Log.v("BindingAdapter", String.valueOf(value));
view.setText(value, 0, value.length);
}
@InverseBindingAdapter(attribute = "android:text")
public static char[] getArrayFromText(ClearableEditText view) {
int length = view.getText().length();
char[] password = new char[length];
view.getText().getChars(0, length, password, 0);
Log.v("BindingAdapter", String.valueOf(password));
return password;
}
}
Emulator behavior :
But the issue is when I enter ABCD in a EditText
I got DCBA displayed plus the focus stay always in the beginning of the EditText
.
Real device behavior :
Only the first char is displayed.
Logs :
2020-02-04 17:37:43.760 4110-4110/com.bla V/InputMethodManager: Starting input: tba=com.bla ic=com.android.internal.widget.EditableInputConnection@3e6e221 mNaviBarColor -16750956 mIsGetNaviBarColorSuccess true , NavVisible : true , NavTrans : false 2020-02-04 17:37:43.760 4110-4110/com.bla D/InputMethodManager: startInputInner - Id : 0 2020-02-04 17:37:43.767 4110-4110/com.bla I/InputMethodManager: startInputInner - mService.startInputOrWindowGainedFocus
IMO CharArray
sucks with databinding because there is no issue when I change CharArray
to String
which mean the equals
method is broken with the genrated code.
@BindingAdapter("android:text")
public static void setCharArray(EditText view, char[] value) {
if(value == null) return;
int length = view.length();
char[] password = new char[length];
view.getText().getChars(0, length, password, 0);
if (Arrays.equals(value, password)) {
Log.v("BindingAdapter out" + view.getId(), String.valueOf(value));
view.setText(value, 0, value.length);
}
}
Edit 1 : Better solution
Use a custom class that implement CharSequence
and hence the adapter version of setText is CharSequence
based there is no need to have a BindingAdapter
in my side.
class SecureString(value: CharArray?) : CharSequence {
@Transient
private val value: CharArray
init {
requireNotNull(value) { "Value must not be null" }
this.value = value
}
override val length: Int
get() = value.size
override fun get(index: Int): Char = value[index]
override fun subSequence(start: Int, end: Int): CharSequence {
throw UnsupportedOperationException()
}
fun clear() {
Arrays.fill(value, '\u0000')
}
fun toCharArray(): CharArray {
return value
}
}
Adapt the InverseBindingAdapter
to return SecureString
:
@InverseBindingAdapter(attribute = "android:text")
public static SecureString getSecureString(EditText view) {
int length = view.length();
SecureString password = new SecureString(new char[length]);
view.getText().getChars(0, length, password.toCharArray(), 0);
return password;
}