diff --git a/app/src/main/java/eu/faircode/email/FragmentAccount.java b/app/src/main/java/eu/faircode/email/FragmentAccount.java index 1bbe4b50eb..a925c3f61f 100644 --- a/app/src/main/java/eu/faircode/email/FragmentAccount.java +++ b/app/src/main/java/eu/faircode/email/FragmentAccount.java @@ -30,7 +30,9 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.text.Editable; import android.text.TextUtils; +import android.text.TextWatcher; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.Menu; @@ -88,6 +90,7 @@ public class FragmentAccount extends FragmentBase { private EditText etPort; private EditText etUser; private TextInputLayout tilPassword; + private TextView tvCharacters; private Button btnOAuth; private TextView tvOAuthSupport; private EditText etRealm; @@ -195,6 +198,7 @@ public class FragmentAccount extends FragmentBase { cbInsecure = view.findViewById(R.id.cbInsecure); etUser = view.findViewById(R.id.etUser); tilPassword = view.findViewById(R.id.tilPassword); + tvCharacters = view.findViewById(R.id.tvCharacters); btnOAuth = view.findViewById(R.id.btnOAuth); tvOAuthSupport = view.findViewById(R.id.tvOAuthSupport); etRealm = view.findViewById(R.id.etRealm); @@ -310,6 +314,28 @@ public class FragmentAccount extends FragmentBase { } }); + tilPassword.getEditText().addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Do nothing + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Do nothing + } + + @Override + public void afterTextChanged(Editable s) { + String password = s.toString(); + boolean warning = (Helper.containsWhiteSpace(password) || + Helper.containsControlChars(password)); + tvCharacters.setVisibility(warning && + tilPassword.getVisibility() == View.VISIBLE + ? View.VISIBLE : View.GONE); + } + }); + btnOAuth.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -436,6 +462,7 @@ public class FragmentAccount extends FragmentBase { rgEncryption.setVisibility(View.GONE); cbInsecure.setVisibility(View.GONE); + tvCharacters.setVisibility(View.GONE); btnAdvanced.setVisibility(View.GONE); diff --git a/app/src/main/java/eu/faircode/email/FragmentIdentity.java b/app/src/main/java/eu/faircode/email/FragmentIdentity.java index 28ee46cf89..5907f5d7d4 100644 --- a/app/src/main/java/eu/faircode/email/FragmentIdentity.java +++ b/app/src/main/java/eu/faircode/email/FragmentIdentity.java @@ -99,6 +99,7 @@ public class FragmentIdentity extends FragmentBase { private EditText etPort; private EditText etUser; private TextInputLayout tilPassword; + private TextView tvCharacters; private Button btnOAuth; private EditText etRealm; private CheckBox cbUseIp; @@ -183,6 +184,7 @@ public class FragmentIdentity extends FragmentBase { etPort = view.findViewById(R.id.etPort); etUser = view.findViewById(R.id.etUser); tilPassword = view.findViewById(R.id.tilPassword); + tvCharacters = view.findViewById(R.id.tvCharacters); btnOAuth = view.findViewById(R.id.btnOAuth); etRealm = view.findViewById(R.id.etRealm); cbUseIp = view.findViewById(R.id.cbUseIp); @@ -292,6 +294,23 @@ public class FragmentIdentity extends FragmentBase { } }); + tilPassword.getEditText().addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Do nothing + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Do nothing + } + + @Override + public void afterTextChanged(Editable s) { + checkPassword(s.toString()); + } + }); + btnColor.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -347,6 +366,7 @@ public class FragmentIdentity extends FragmentBase { public void onClick(View v) { int visibility = (grpAdvanced.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE); grpAdvanced.setVisibility(visibility); + checkPassword(tilPassword.getEditText().getText().toString()); if (visibility == View.VISIBLE) new Handler().post(new Runnable() { @Override @@ -452,6 +472,7 @@ public class FragmentIdentity extends FragmentBase { btnAutoConfig.setEnabled(false); pbAutoConfig.setVisibility(View.GONE); cbInsecure.setVisibility(View.GONE); + tvCharacters.setVisibility(View.GONE); btnAdvanced.setVisibility(View.GONE); @@ -515,6 +536,15 @@ public class FragmentIdentity extends FragmentBase { }.execute(this, args, "identity:config"); } + private void checkPassword(String password) { + boolean warning = (Helper.containsWhiteSpace(password) || + Helper.containsControlChars(password)); + tvCharacters.setVisibility(warning && + grpAdvanced.getVisibility() == View.VISIBLE + ? View.VISIBLE : View.GONE); + + } + private void onSave(boolean should) { EntityAccount account = (EntityAccount) spAccount.getSelectedItem(); diff --git a/app/src/main/java/eu/faircode/email/FragmentPop.java b/app/src/main/java/eu/faircode/email/FragmentPop.java index 27ffcb91b7..43bc2d97aa 100644 --- a/app/src/main/java/eu/faircode/email/FragmentPop.java +++ b/app/src/main/java/eu/faircode/email/FragmentPop.java @@ -26,7 +26,9 @@ import android.graphics.Color; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.text.Editable; import android.text.TextUtils; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -64,6 +66,7 @@ public class FragmentPop extends FragmentBase { private EditText etPort; private EditText etUser; private TextInputLayout tilPassword; + private TextView tvCharacters; private EditText etName; private ViewButtonColor btnColor; @@ -113,6 +116,7 @@ public class FragmentPop extends FragmentBase { cbInsecure = view.findViewById(R.id.cbInsecure); etUser = view.findViewById(R.id.etUser); tilPassword = view.findViewById(R.id.tilPassword); + tvCharacters = view.findViewById(R.id.tvCharacters); etName = view.findViewById(R.id.etName); btnColor = view.findViewById(R.id.btnColor); @@ -132,6 +136,28 @@ public class FragmentPop extends FragmentBase { pbWait = view.findViewById(R.id.pbWait); + tilPassword.getEditText().addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Do nothing + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Do nothing + } + + @Override + public void afterTextChanged(Editable s) { + String password = s.toString(); + boolean warning = (Helper.containsWhiteSpace(password) || + Helper.containsControlChars(password)); + tvCharacters.setVisibility(warning && + tilPassword.getVisibility() == View.VISIBLE + ? View.VISIBLE : View.GONE); + } + }); + btnColor.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -169,6 +195,7 @@ public class FragmentPop extends FragmentBase { // Initialize Helper.setViewsEnabled(view, false); + tvCharacters.setVisibility(View.GONE); pbSave.setVisibility(View.GONE); grpError.setVisibility(View.GONE); diff --git a/app/src/main/java/eu/faircode/email/FragmentQuickSetup.java b/app/src/main/java/eu/faircode/email/FragmentQuickSetup.java index d09ac08ec2..a638fd45f1 100644 --- a/app/src/main/java/eu/faircode/email/FragmentQuickSetup.java +++ b/app/src/main/java/eu/faircode/email/FragmentQuickSetup.java @@ -24,7 +24,9 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.text.Editable; import android.text.TextUtils; +import android.text.TextWatcher; import android.text.method.LinkMovementMethod; import android.util.Patterns; import android.view.KeyEvent; @@ -59,6 +61,7 @@ public class FragmentQuickSetup extends FragmentBase { private EditText etName; private EditText etEmail; private TextInputLayout tilPassword; + private TextView tvCharacters; private Button btnCheck; private ContentLoadingProgressBar pbCheck; @@ -88,6 +91,7 @@ public class FragmentQuickSetup extends FragmentBase { etName = view.findViewById(R.id.etName); etEmail = view.findViewById(R.id.etEmail); tilPassword = view.findViewById(R.id.tilPassword); + tvCharacters = view.findViewById(R.id.tvCharacters); btnCheck = view.findViewById(R.id.btnCheck); pbCheck = view.findViewById(R.id.pbCheck); @@ -119,6 +123,28 @@ public class FragmentQuickSetup extends FragmentBase { } }); + tilPassword.getEditText().addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Do nothing + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Do nothing + } + + @Override + public void afterTextChanged(Editable s) { + String password = s.toString(); + boolean warning = (Helper.containsWhiteSpace(password) || + Helper.containsControlChars(password)); + tvCharacters.setVisibility(warning && + tilPassword.getVisibility() == View.VISIBLE + ? View.VISIBLE : View.GONE); + } + }); + btnCheck.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -149,6 +175,7 @@ public class FragmentQuickSetup extends FragmentBase { }); // Initialize + tvCharacters.setVisibility(View.GONE); pbCheck.setVisibility(View.GONE); pbSave.setVisibility(View.GONE); btnHelp.setVisibility(View.GONE); diff --git a/app/src/main/java/eu/faircode/email/Helper.java b/app/src/main/java/eu/faircode/email/Helper.java index ba95092473..da5e96773b 100644 --- a/app/src/main/java/eu/faircode/email/Helper.java +++ b/app/src/main/java/eu/faircode/email/Helper.java @@ -584,6 +584,26 @@ public class Helper { return result.toArray(new String[0]); } + static boolean containsWhiteSpace(String text) { + return text.matches(".*\\s+.*"); + } + + static boolean containsControlChars(String text) { + for (int offset = 0; offset < text.length(); ) { + int codePoint = text.codePointAt(offset); + offset += Character.charCount(codePoint); + switch (Character.getType(codePoint)) { + case Character.CONTROL: // \p{Cc} + case Character.FORMAT: // \p{Cf} + case Character.PRIVATE_USE: // \p{Co} + case Character.SURROGATE: // \p{Cs} + case Character.UNASSIGNED: // \p{Cn} + return true; + } + } + return false; + } + // Files static String sanitizeFilename(String name) { diff --git a/app/src/main/res/layout/fragment_account.xml b/app/src/main/res/layout/fragment_account.xml index e44298dab7..bc802118c8 100644 --- a/app/src/main/res/layout/fragment_account.xml +++ b/app/src/main/res/layout/fragment_account.xml @@ -243,6 +243,18 @@ android:textAppearance="@style/TextAppearance.AppCompat.Medium" /> + +