Merge branch '2175-mailbox-problem-notification' into 'master'

Show notification warning when own mailbox is unreachable

Closes #2175

See merge request briar/briar!1648
This commit is contained in:
akwizgran
2022-05-26 20:10:13 +00:00
16 changed files with 133 additions and 10 deletions

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.mailbox;
import static java.util.concurrent.TimeUnit.HOURS;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_PAYLOAD_LENGTH;
import static org.briarproject.bramble.api.transport.TransportConstants.STREAM_HEADER_LENGTH;
@@ -20,4 +21,17 @@ public interface MailboxConstants {
int MAX_FILE_PAYLOAD_BYTES =
(MAX_FILE_BYTES - TAG_LENGTH - STREAM_HEADER_LENGTH)
/ MAX_FRAME_LENGTH * MAX_PAYLOAD_LENGTH;
/**
* The number of connection failures
* that indicate a problem with the mailbox.
*/
int PROBLEM_NUM_CONNECTION_FAILURES = 5;
/**
* The time in milliseconds since the last connection success
* that need to pass to indicates a problem with the mailbox.
*/
long PROBLEM_MS_SINCE_LAST_SUCCESS = HOURS.toMillis(1);
}

View File

@@ -3,6 +3,7 @@ package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
import javax.annotation.Nullable;

View File

@@ -4,6 +4,9 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.PROBLEM_MS_SINCE_LAST_SUCCESS;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.PROBLEM_NUM_CONNECTION_FAILURES;
@Immutable
@NotNullByDefault
public class MailboxStatus {
@@ -56,4 +59,12 @@ public class MailboxStatus {
public int getAttemptsSinceSuccess() {
return attemptsSinceSuccess;
}
/**
* @return true if this status indicates a problem with the mailbox.
*/
public boolean hasProblem(long now) {
return attemptsSinceSuccess >= PROBLEM_NUM_CONNECTION_FAILURES &&
(now - lastSuccess) >= PROBLEM_MS_SINCE_LAST_SUCCESS;
}
}

View File

@@ -0,0 +1,19 @@
package org.briarproject.bramble.api.mailbox.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast by {@link MailboxSettingsManager} when
* recording a connection failure for own Mailbox
* that has persistent for long enough for the mailbox owner to become active
* and fix the problem with the mailbox.
*/
@Immutable
@NotNullByDefault
public class MailboxProblemEvent extends Event {
}

View File

@@ -1,6 +1,8 @@
package org.briarproject.bramble.api.mailbox;
package org.briarproject.bramble.api.mailbox.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;

View File

@@ -1,7 +1,8 @@
package org.briarproject.bramble.api.mailbox;
package org.briarproject.bramble.api.mailbox.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;

View File

@@ -9,7 +9,8 @@ import org.briarproject.bramble.api.mailbox.MailboxProperties;
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.bramble.api.mailbox.MailboxVersion;
import org.briarproject.bramble.api.mailbox.OwnMailboxConnectionStatusEvent;
import org.briarproject.bramble.api.mailbox.event.MailboxProblemEvent;
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.SettingsManager;
@@ -141,6 +142,7 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager {
settingsManager.mergeSettings(txn, newSettings, SETTINGS_NAMESPACE);
MailboxStatus status = new MailboxStatus(now, lastSuccess, newAttempts);
txn.attach(new OwnMailboxConnectionStatusEvent(status));
if (status.hasProblem(now)) txn.attach(new MailboxProblemEvent());
}
@Override

View File

@@ -25,7 +25,7 @@ import org.briarproject.bramble.api.mailbox.MailboxUpdate;
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
import org.briarproject.bramble.api.mailbox.MailboxVersion;
import org.briarproject.bramble.api.mailbox.RemoteMailboxUpdateEvent;
import org.briarproject.bramble.api.mailbox.event.RemoteMailboxUpdateEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Group.Visibility;

View File

@@ -13,7 +13,7 @@ import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
import org.briarproject.bramble.api.mailbox.MailboxUpdateManager;
import org.briarproject.bramble.api.mailbox.MailboxVersion;
import org.briarproject.bramble.api.mailbox.OwnMailboxConnectionStatusEvent;
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations;

View File

@@ -7,7 +7,7 @@ import org.briarproject.bramble.api.mailbox.MailboxProperties;
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.bramble.api.mailbox.MailboxVersion;
import org.briarproject.bramble.api.mailbox.OwnMailboxConnectionStatusEvent;
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.test.BrambleMockTestCase;

View File

@@ -18,7 +18,7 @@ import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.mailbox.MailboxUpdate;
import org.briarproject.bramble.api.mailbox.MailboxUpdateWithMailbox;
import org.briarproject.bramble.api.mailbox.MailboxVersion;
import org.briarproject.bramble.api.mailbox.RemoteMailboxUpdateEvent;
import org.briarproject.bramble.api.mailbox.event.RemoteMailboxUpdateEvent;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;

View File

@@ -18,6 +18,9 @@ import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.lifecycle.ServiceException;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.bramble.api.mailbox.event.MailboxProblemEvent;
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.settings.Settings;
@@ -32,6 +35,7 @@ import org.briarproject.briar.android.conversation.ConversationActivity;
import org.briarproject.briar.android.forum.ForumActivity;
import org.briarproject.briar.android.hotspot.HotspotActivity;
import org.briarproject.briar.android.login.SignInReminderReceiver;
import org.briarproject.briar.android.mailbox.MailboxActivity;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
import org.briarproject.briar.android.splash.SplashScreenActivity;
@@ -69,10 +73,12 @@ import static android.content.Context.NOTIFICATION_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.net.Uri.EMPTY;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.core.app.NotificationCompat.CATEGORY_MESSAGE;
import static androidx.core.app.NotificationCompat.CATEGORY_SERVICE;
import static androidx.core.app.NotificationCompat.CATEGORY_SOCIAL;
import static androidx.core.app.NotificationCompat.PRIORITY_HIGH;
import static androidx.core.app.NotificationCompat.PRIORITY_LOW;
import static androidx.core.app.NotificationCompat.PRIORITY_MIN;
import static androidx.core.app.NotificationCompat.VISIBILITY_SECRET;
@@ -182,6 +188,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
clearForumPostNotification();
clearBlogPostNotification();
clearContactAddedNotification();
clearMailboxProblemNotification();
return null;
});
try {
@@ -250,6 +257,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
ContactAddedEvent c = (ContactAddedEvent) e;
// Don't show notifications for contacts added in person
if (!c.isVerified()) showContactAddedNotification();
} else if (e instanceof MailboxProblemEvent) {
showMailboxProblemNotification();
} else if (e instanceof OwnMailboxConnectionStatusEvent) {
MailboxStatus s = ((OwnMailboxConnectionStatusEvent) e).getStatus();
if (s.getAttemptsSinceSuccess() == 0) {
clearMailboxProblemNotification();
}
}
}
@@ -757,4 +771,45 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
public void clearHotspotNotification() {
notificationManager.cancel(HOTSPOT_NOTIFICATION_ID);
}
@Override
public void showMailboxProblemNotification() {
if (SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(
MAILBOX_PROBLEM_CHANNEL_ID, appContext.getString(
R.string.mailbox_error_notification_channel_title),
IMPORTANCE_DEFAULT);
channel.setLockscreenVisibility(VISIBILITY_SECRET);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder b = new NotificationCompat.Builder(
appContext, MAILBOX_PROBLEM_CHANNEL_ID);
b.setSmallIcon(R.drawable.ic_mailbox);
b.setColor(getColor(appContext, R.color.briar_red_500));
b.setContentTitle(
appContext.getText(R.string.mailbox_error_notification_title));
b.setContentText(
appContext.getText(R.string.mailbox_error_notification_text));
b.setAutoCancel(true);
b.setNotificationSilent(); // not important enough for sound
b.setWhen(0); // Don't show the time
b.setPriority(PRIORITY_HIGH);
// Touching the notification shows the mailbox status page
Intent i = new Intent(appContext, MailboxActivity.class);
i.setData(EMPTY); // for some reason, the back navigation needs an Uri
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
TaskStackBuilder t = TaskStackBuilder.create(appContext);
t.addParentStack(MailboxActivity.class);
t.addNextIntent(i);
b.setContentIntent(t.getPendingIntent(nextRequestId++, 0));
notificationManager.notify(MAILBOX_PROBLEM_NOTIFICATION_ID, b.build());
}
@Override
public void clearMailboxProblemNotification() {
notificationManager.cancel(MAILBOX_PROBLEM_NOTIFICATION_ID);
}
}

View File

@@ -117,6 +117,7 @@ public class MailboxStatusFragment extends Fragment {
public void onStart() {
super.onStart();
requireActivity().setTitle(R.string.mailbox_status_title);
viewModel.clearProblemNotification();
refresher = this::refreshLastConnection;
handler.postDelayed(refresher, MIN_DATE_RESOLUTION);
}
@@ -138,7 +139,7 @@ public class MailboxStatusFragment extends Fragment {
tintRes = R.color.briar_brand_green;
showUnlinkWarning = true;
wizardButton.setVisibility(GONE);
} else if (status.getAttemptsSinceSuccess() < NUM_FAILURES) {
} else if (!status.hasProblem(System.currentTimeMillis())) {
iconRes = R.drawable.ic_help_outline_white;
title = getString(R.string.mailbox_status_problem_title);
tintRes = R.color.briar_orange_500;

View File

@@ -17,7 +17,7 @@ import org.briarproject.bramble.api.mailbox.MailboxManager;
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
import org.briarproject.bramble.api.mailbox.MailboxPairingTask;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.bramble.api.mailbox.OwnMailboxConnectionStatusEvent;
import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.PluginManager;
@@ -30,6 +30,7 @@ import org.briarproject.briar.android.qrcode.QrCodeDecoder;
import org.briarproject.briar.android.viewmodel.DbViewModel;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import org.briarproject.briar.api.android.AndroidNotificationManager;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
@@ -59,6 +60,7 @@ class MailboxViewModel extends DbViewModel
private final QrCodeDecoder qrCodeDecoder;
private final PluginManager pluginManager;
private final MailboxManager mailboxManager;
private final AndroidNotificationManager notificationManager;
private final MutableLiveEvent<MailboxState> pairingState =
new MutableLiveEvent<>();
@@ -77,12 +79,14 @@ class MailboxViewModel extends DbViewModel
EventBus eventBus,
@IoExecutor Executor ioExecutor,
PluginManager pluginManager,
MailboxManager mailboxManager) {
MailboxManager mailboxManager,
AndroidNotificationManager notificationManager) {
super(app, dbExecutor, lifecycleManager, db, androidExecutor);
this.eventBus = eventBus;
this.ioExecutor = ioExecutor;
this.pluginManager = pluginManager;
this.mailboxManager = mailboxManager;
this.notificationManager = notificationManager;
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
eventBus.addListener(this);
checkIfSetup();
@@ -251,6 +255,10 @@ class MailboxViewModel extends DbViewModel
});
}
void clearProblemNotification() {
notificationManager.clearMailboxProblemNotification();
}
@UiThread
LiveEvent<MailboxState> getPairingState() {
return pairingState;

View File

@@ -32,6 +32,7 @@ public interface AndroidNotificationManager {
int BLOG_POST_NOTIFICATION_ID = 7;
int CONTACT_ADDED_NOTIFICATION_ID = 8;
int HOTSPOT_NOTIFICATION_ID = 9;
int MAILBOX_PROBLEM_NOTIFICATION_ID = 10;
// Channel IDs
String CONTACT_CHANNEL_ID = "contacts";
@@ -44,6 +45,7 @@ public interface AndroidNotificationManager {
String ONGOING_CHANNEL_ID = "zForegroundService2";
String REMINDER_CHANNEL_ID = "zSignInReminder";
String HOTSPOT_CHANNEL_ID = "zHotspot";
String MAILBOX_PROBLEM_CHANNEL_ID = "zMailboxProblem";
// This channel is no longer used - keep the ID so we can remove the
// channel from existing installations
@@ -104,4 +106,8 @@ public interface AndroidNotificationManager {
void showHotspotNotification();
void clearHotspotNotification();
void showMailboxProblemNotification();
void clearMailboxProblemNotification();
}

View File

@@ -652,6 +652,9 @@
<string name="mailbox_status_unlink_no_wipe_title">Your Mailbox has been unlinked</string>
<string name="mailbox_status_unlink_no_wipe_message">Next time you have access to your Mailbox device, please open the Mailbox app and tap the \"Unlink\" button to complete the process.\n\nIf you no longer have access to your Mailbox device, don\'t worry. Your data is encrypted so it will remain secure even if you don\'t complete the process.</string>
<string name="mailbox_error_notification_channel_title">Briar Mailbox problem</string>
<string name="mailbox_error_notification_title">Briar Mailbox is unavailable</string>
<string name="mailbox_error_notification_text">Tap to fix problem.</string>
<string name="mailbox_error_wizard_button">Fix problem</string>
<string name="mailbox_error_wizard_title">Mailbox troubleshooting wizard</string>
<string name="mailbox_error_wizard_question1">Do you have access to your Mailbox device?</string>