Improved error handling

This commit is contained in:
M66B 2019-06-20 08:39:37 +02:00
parent c81389769e
commit ce9b7e82e2
13 changed files with 100 additions and 76 deletions

6
FAQ.md
View File

@ -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.

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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 {

View File

@ -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());

View File

@ -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());

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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" />

View File

@ -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>

View File

@ -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"

View File

@ -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" />