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" />
+
+
+ app:layout_constraintTop_toBottomOf="@id/tvCharacters" />
+
+
+ app:layout_constraintTop_toBottomOf="@id/tvCharacters" />
+
+
+ app:layout_constraintTop_toBottomOf="@id/tvCharacters" />
+
+
+ app:layout_constraintTop_toBottomOf="@id/tvCharacters" />