mirror of https://github.com/M66B/FairEmail.git
Improved error handling
This commit is contained in:
parent
c81389769e
commit
ce9b7e82e2
6
FAQ.md
6
FAQ.md
|
@ -334,7 +334,11 @@ Unfortunately, it is impossible to make everybody happy and adding lots of setti
|
|||
To use a Gmail/G suite account, you'll need to enable access for "less secure" apps,
|
||||
see [here](https://support.google.com/accounts/answer/6010255) for Google's instructions
|
||||
or go [directy to the setting](https://www.google.com/settings/security/lesssecureapps).
|
||||
You can solve the error *535-5.7.8 Username and Password not accepted* by enabling "less secure" apps.
|
||||
When "less secure" apps is not enabled,
|
||||
you'll get the error *Authentication failed - invalid credentials* for accounts (IMAP)
|
||||
and *Username and Password not accepted* for identities (SMTP).
|
||||
|
||||
If you use multiple Gmail accounts, make sure you change the "less secure" setting of the right account.
|
||||
|
||||
You might get the alert "*Please log in via your web browser*".
|
||||
This security measure can for example be triggered when too many IP addresses were used in a too short time or when you are using a VPN.
|
||||
|
|
|
@ -448,15 +448,7 @@ public class ActivityView extends ActivityBilling implements FragmentManager.OnB
|
|||
|
||||
} else if ("outbox".equals(action))
|
||||
onMenuOutbox();
|
||||
|
||||
else if ("error".equals(action)) {
|
||||
Intent ifaq = new Intent(Intent.ACTION_VIEW);
|
||||
ifaq.setData(Uri.parse(Helper.FAQ_URI + "#frequently-asked-questions"));
|
||||
ifaq.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
if (ifaq.resolveActivity(getPackageManager()) != null)
|
||||
startActivity(ifaq);
|
||||
|
||||
} else if (action.startsWith("thread")) {
|
||||
else if (action.startsWith("thread")) {
|
||||
intent.putExtra("thread", action.split(":", 2)[1]);
|
||||
onViewThread(intent);
|
||||
}
|
||||
|
|
|
@ -3069,6 +3069,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
|
|||
message.id = null;
|
||||
message.folder = drafts.id;
|
||||
message.ui_snoozed = null;
|
||||
message.error = null;
|
||||
message.id = db.message().insertMessage(message);
|
||||
|
||||
File target = message.getFile(context);
|
||||
|
|
|
@ -2129,11 +2129,11 @@ class Core {
|
|||
|
||||
String title;
|
||||
if (account == null)
|
||||
title = folder.name;
|
||||
title = Helper.localizeFolderName(context, folder.name);
|
||||
else if (folder == null)
|
||||
title = account.name;
|
||||
else
|
||||
title = account.name + "/" + folder.name;
|
||||
title = account.name + "/" + Helper.localizeFolderName(context, folder.name);
|
||||
|
||||
String tag = "error:" + (account == null ? 0 : account.id) + ":" + (folder == null ? 0 : folder.id);
|
||||
|
||||
|
@ -2146,7 +2146,7 @@ class Core {
|
|||
if (ex instanceof AuthenticationFailedException || // Also: Too many simultaneous connections
|
||||
ex instanceof AlertException ||
|
||||
ex instanceof SendFailedException)
|
||||
nm.notify(tag, 1, getNotificationError(context, title, ex).build());
|
||||
nm.notify(tag, 1, getNotificationError(context, "error", title, ex).build());
|
||||
|
||||
// connection failure: Too many simultaneous connections
|
||||
|
||||
|
@ -2164,18 +2164,12 @@ class Core {
|
|||
!(ex instanceof MessagingException && ex.getCause() instanceof SocketTimeoutException) &&
|
||||
!(ex instanceof MessagingException && ex.getCause() instanceof SSLException) &&
|
||||
!(ex instanceof MessagingException && "connection failure".equals(ex.getMessage())))
|
||||
nm.notify(tag, 1, getNotificationError(context, title, ex).build());
|
||||
nm.notify(tag, 1, getNotificationError(context, "error", title, ex).build());
|
||||
}
|
||||
|
||||
static NotificationCompat.Builder getNotificationError(Context context, String title, Throwable ex) {
|
||||
return getNotificationError(context, "error", title, ex, true);
|
||||
}
|
||||
|
||||
static NotificationCompat.Builder getNotificationError(Context context, String channel, String title, Throwable ex, boolean debug) {
|
||||
static NotificationCompat.Builder getNotificationError(Context context, String channel, String title, Throwable ex) {
|
||||
// Build pending intent
|
||||
Intent intent = new Intent(context, ActivityView.class);
|
||||
if (debug)
|
||||
intent.setAction("error");
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent pi = PendingIntent.getActivity(
|
||||
context, ActivityView.REQUEST_ERROR, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
|
|
@ -156,6 +156,7 @@ public class EntityOperation {
|
|||
boolean seen = message.seen;
|
||||
boolean ui_seen = message.ui_seen;
|
||||
boolean ui_browsed = message.ui_browsed;
|
||||
String error = message.error;
|
||||
|
||||
message.id = null;
|
||||
message.account = target.account;
|
||||
|
@ -167,6 +168,7 @@ public class EntityOperation {
|
|||
message.ui_seen = true;
|
||||
}
|
||||
message.ui_browsed = false;
|
||||
message.error = null;
|
||||
message.id = db.message().insertMessage(message);
|
||||
File mtarget = message.getFile(context);
|
||||
long tmpid = message.id;
|
||||
|
@ -179,6 +181,7 @@ public class EntityOperation {
|
|||
message.seen = seen;
|
||||
message.ui_seen = ui_seen;
|
||||
message.ui_browsed = ui_browsed;
|
||||
message.error = error;
|
||||
|
||||
if (message.content)
|
||||
try {
|
||||
|
|
|
@ -639,27 +639,8 @@ public class FragmentAccount extends FragmentBase {
|
|||
|
||||
if (ex instanceof IllegalArgumentException)
|
||||
Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
else {
|
||||
tvError.setText(Helper.formatThrowable(ex));
|
||||
tvError.setVisibility(View.VISIBLE);
|
||||
|
||||
final View target;
|
||||
|
||||
EmailProvider provider = (EmailProvider) spProvider.getSelectedItem();
|
||||
if (provider != null && provider.documentation != null) {
|
||||
tvInstructions.setText(HtmlHelper.fromHtml(provider.documentation.toString()));
|
||||
tvInstructions.setVisibility(View.VISIBLE);
|
||||
target = tvInstructions;
|
||||
} else
|
||||
target = tvError;
|
||||
|
||||
new Handler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scroll.smoothScrollTo(0, target.getBottom());
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
showError(ex);
|
||||
}
|
||||
}.execute(FragmentAccount.this, args, "account:check");
|
||||
}
|
||||
|
@ -858,9 +839,11 @@ public class FragmentAccount extends FragmentBase {
|
|||
String accountRealm = (account == null ? null : account.realm);
|
||||
|
||||
boolean check = (synchronize && (account == null ||
|
||||
!account.synchronize ||
|
||||
!host.equals(account.host) || Integer.parseInt(port) != account.port ||
|
||||
!user.equals(account.user) || !password.equals(account.password) ||
|
||||
!Objects.equals(realm, accountRealm)));
|
||||
!Objects.equals(realm, accountRealm) ||
|
||||
!TextUtils.isEmpty(account.error)));
|
||||
boolean reload = (check || account == null ||
|
||||
account.synchronize != synchronize ||
|
||||
account.notify != notify ||
|
||||
|
@ -1078,20 +1061,34 @@ public class FragmentAccount extends FragmentBase {
|
|||
protected void onException(Bundle args, Throwable ex) {
|
||||
if (ex instanceof IllegalArgumentException)
|
||||
Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
else {
|
||||
tvError.setText(Helper.formatThrowable(ex));
|
||||
tvError.setVisibility(View.VISIBLE);
|
||||
new Handler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scroll.smoothScrollTo(0, tvError.getBottom());
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
showError(ex);
|
||||
}
|
||||
}.execute(FragmentAccount.this, args, "account:save");
|
||||
}
|
||||
|
||||
private void showError(Throwable ex) {
|
||||
tvError.setText(Helper.formatThrowable(ex));
|
||||
tvError.setVisibility(View.VISIBLE);
|
||||
|
||||
final View target;
|
||||
|
||||
EmailProvider provider = (EmailProvider) spProvider.getSelectedItem();
|
||||
if (provider != null && provider.documentation != null) {
|
||||
tvInstructions.setText(HtmlHelper.fromHtml(provider.documentation.toString()));
|
||||
tvInstructions.setVisibility(View.VISIBLE);
|
||||
target = tvInstructions;
|
||||
} else
|
||||
target = tvError;
|
||||
|
||||
new Handler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scroll.smoothScrollTo(0, target.getBottom());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putInt("fair:provider", spProvider.getSelectedItemPosition());
|
||||
|
|
|
@ -29,6 +29,7 @@ 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.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -117,6 +118,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
private Button btnSave;
|
||||
private ContentLoadingProgressBar pbSave;
|
||||
private TextView tvError;
|
||||
private TextView tvInstructions;
|
||||
|
||||
private ContentLoadingProgressBar pbWait;
|
||||
|
||||
|
@ -187,6 +189,8 @@ public class FragmentIdentity extends FragmentBase {
|
|||
btnSave = view.findViewById(R.id.btnSave);
|
||||
pbSave = view.findViewById(R.id.pbSave);
|
||||
tvError = view.findViewById(R.id.tvError);
|
||||
tvInstructions = view.findViewById(R.id.tvInstructions);
|
||||
tvInstructions.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
pbWait = view.findViewById(R.id.pbWait);
|
||||
|
||||
|
@ -201,6 +205,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
grpAuthorize.setVisibility(position > 0 ? View.VISIBLE : View.GONE);
|
||||
if (position == 0) {
|
||||
tvError.setVisibility(View.GONE);
|
||||
tvInstructions.setVisibility(View.GONE);
|
||||
grpAdvanced.setVisibility(View.GONE);
|
||||
}
|
||||
tilPassword.setEndIconMode(position == 0 ? END_ICON_PASSWORD_TOGGLE : END_ICON_NONE);
|
||||
|
@ -429,6 +434,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
btnSave.setVisibility(View.GONE);
|
||||
pbSave.setVisibility(View.GONE);
|
||||
tvError.setVisibility(View.GONE);
|
||||
tvInstructions.setVisibility(View.GONE);
|
||||
|
||||
grpAuthorize.setVisibility(View.GONE);
|
||||
grpAdvanced.setVisibility(View.GONE);
|
||||
|
@ -525,6 +531,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
Helper.setViewsEnabled(view, false);
|
||||
pbSave.setVisibility(View.VISIBLE);
|
||||
tvError.setVisibility(View.GONE);
|
||||
tvInstructions.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -659,10 +666,12 @@ public class FragmentIdentity extends FragmentBase {
|
|||
String identityRealm = (identity == null ? null : identity.realm);
|
||||
|
||||
boolean check = (synchronize && (identity == null ||
|
||||
!identity.synchronize ||
|
||||
!host.equals(identity.host) || Integer.parseInt(port) != identity.port ||
|
||||
!user.equals(identity.user) || !password.equals(identity.password) ||
|
||||
!Objects.equals(realm, identityRealm) ||
|
||||
use_ip != identity.use_ip));
|
||||
use_ip != identity.use_ip) ||
|
||||
!TextUtils.isEmpty(identity.error));
|
||||
|
||||
Long last_connected = null;
|
||||
if (identity != null && synchronize == identity.synchronize)
|
||||
|
@ -784,20 +793,34 @@ public class FragmentIdentity extends FragmentBase {
|
|||
protected void onException(Bundle args, Throwable ex) {
|
||||
if (ex instanceof IllegalArgumentException)
|
||||
Snackbar.make(view, ex.getMessage(), Snackbar.LENGTH_LONG).show();
|
||||
else {
|
||||
tvError.setText(Helper.formatThrowable(ex));
|
||||
tvError.setVisibility(View.VISIBLE);
|
||||
new Handler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scroll.smoothScrollTo(0, tvError.getBottom());
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
showError(ex);
|
||||
}
|
||||
}.execute(FragmentIdentity.this, args, "identity:save");
|
||||
}
|
||||
|
||||
private void showError(Throwable ex) {
|
||||
tvError.setText(Helper.formatThrowable(ex));
|
||||
tvError.setVisibility(View.VISIBLE);
|
||||
|
||||
final View target;
|
||||
|
||||
EmailProvider provider = (EmailProvider) spProvider.getSelectedItem();
|
||||
if (provider != null && provider.documentation != null) {
|
||||
tvInstructions.setText(HtmlHelper.fromHtml(provider.documentation.toString()));
|
||||
tvInstructions.setVisibility(View.VISIBLE);
|
||||
target = tvInstructions;
|
||||
} else
|
||||
target = tvError;
|
||||
|
||||
new Handler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
scroll.smoothScrollTo(0, target.getBottom());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putInt("fair:account", spAccount.getSelectedItemPosition());
|
||||
|
|
|
@ -416,7 +416,7 @@ public class ServiceSend extends LifecycleService {
|
|||
Log.i("Reporting send error after=" + delayed);
|
||||
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify("send", message.identity.intValue(),
|
||||
Core.getNotificationError(this, ident.name, ex).build());
|
||||
Core.getNotificationError(this, "error", ident.name, ex).build());
|
||||
}
|
||||
|
||||
throw ex;
|
||||
|
|
|
@ -711,7 +711,7 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
.format(account.last_connected)), ex);
|
||||
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify("receive", account.id.intValue(),
|
||||
Core.getNotificationError(this, "warning", account.name, warning, false)
|
||||
Core.getNotificationError(this, "warning", account.name, warning)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -707,7 +707,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="provider instructions"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvError" />
|
||||
|
||||
|
|
|
@ -36,10 +36,10 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/title_legend_close_hint"
|
||||
app:srcCompat="@drawable/baseline_close_24"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvHintActions"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/tvHintActions" />
|
||||
app:layout_constraintTop_toTopOf="@id/tvHintActions"
|
||||
app:srcCompat="@drawable/baseline_close_24" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorActions"
|
||||
|
@ -71,10 +71,10 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/title_legend_close_hint"
|
||||
app:srcCompat="@drawable/baseline_close_24"
|
||||
app:layout_constraintBottom_toBottomOf="@id/tvHintSync"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/tvHintSync" />
|
||||
app:layout_constraintTop_toTopOf="@id/tvHintSync"
|
||||
app:srcCompat="@drawable/baseline_close_24" />
|
||||
|
||||
<View
|
||||
android:id="@+id/vSeparatorSync"
|
||||
|
@ -135,10 +135,10 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_margin="@dimen/fab_padding"
|
||||
app:srcCompat="@drawable/baseline_create_new_folder_24"
|
||||
android:tint="@color/colorActionForeground"
|
||||
android:tooltipText="@string/title_add"
|
||||
app:backgroundTint="?attr/colorAccent" />
|
||||
app:backgroundTint="?attr/colorAccent"
|
||||
app:srcCompat="@drawable/baseline_create_new_folder_24" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fabError"
|
||||
|
@ -146,8 +146,8 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:layout_margin="@dimen/fab_padding"
|
||||
v="@drawable/baseline_warning_24"
|
||||
android:tint="@color/colorActionForeground"
|
||||
android:tooltipText="@string/title_compose"
|
||||
app:backgroundTint="@color/lightColorWarning" />
|
||||
app:backgroundTint="@color/lightColorWarning"
|
||||
app:srcCompat="@drawable/baseline_warning_24" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
@ -612,6 +612,16 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btnSave" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvInstructions"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="provider instructions"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvError" />
|
||||
|
||||
<eu.faircode.email.ContentLoadingProgressBar
|
||||
android:id="@+id/pbWait"
|
||||
style="@style/Base.Widget.AppCompat.ProgressBar"
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="provider instructions"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvError" />
|
||||
|
||||
|
|
Loading…
Reference in New Issue