Use new MailboxManager in Android UI

This commit is contained in:
Torsten Grote
2022-02-17 14:22:56 -03:00
parent 7fad299cf0
commit 80d804d280
3 changed files with 123 additions and 109 deletions

View File

@@ -5,6 +5,8 @@ import android.view.MenuItem;
import android.widget.ProgressBar;
import android.widget.Toast;
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
import org.briarproject.bramble.api.mailbox.MailboxPairingState.Pairing;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
@@ -20,6 +22,7 @@ import androidx.lifecycle.ViewModelProvider;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_LONG;
import static org.briarproject.briar.android.util.UiUtils.showFragment;
@MethodsNotNullByDefault
@@ -55,14 +58,14 @@ public class MailboxActivity extends BriarActivity {
onNotSetup();
} else if (state instanceof MailboxState.ScanningQrCode) {
onScanningQrCode();
} else if (state instanceof MailboxState.SettingUp) {
onCodeScanned();
} else if (state instanceof MailboxState.QrCodeWrong) {
onQrCodeWrong();
} else if (state instanceof MailboxState.OfflineInSetup) {
} else if (state instanceof MailboxState.Pairing) {
MailboxPairingState s =
((MailboxState.Pairing) state).pairingState;
onMailboxPairingStateChanged(s);
} else if (state instanceof MailboxState.OfflineWhenPairing) {
onOffline();
} else if (state instanceof MailboxState.IsSetup) {
onIsSetup(((MailboxState.IsSetup) state).mailboxStatus);
} else if (state instanceof MailboxState.IsPaired) {
onIsPaired(((MailboxState.IsPaired) state).mailboxStatus);
} else {
throw new AssertionError("Unknown state: " + state);
}
@@ -80,9 +83,10 @@ public class MailboxActivity extends BriarActivity {
@Override
public void onBackPressed() {
if (viewModel.getState()
.getLastValue() instanceof MailboxState.SettingUp) {
// don't go back in flow if we are already setting up mailbox
MailboxState s = viewModel.getState().getLastValue();
if (s instanceof MailboxState.Pairing &&
((MailboxState.Pairing) s).pairingState instanceof Pairing) {
// don't go back in flow if we are already pairing with the mailbox
supportFinishAfterTransition();
} else {
super.onBackPressed();
@@ -102,17 +106,43 @@ public class MailboxActivity extends BriarActivity {
MailboxScanFragment.TAG);
}
private void onCodeScanned() {
showFragment(getSupportFragmentManager(),
new MailboxConnectingFragment(),
MailboxConnectingFragment.TAG, false);
}
private void onQrCodeWrong() {
Fragment f = ErrorFragment.newInstance(
R.string.mailbox_setup_qr_code_wrong_title,
R.string.mailbox_setup_qr_code_wrong_description);
showFragment(getSupportFragmentManager(), f, ErrorFragment.TAG);
private void onMailboxPairingStateChanged(MailboxPairingState s) {
progressBar.setVisibility(INVISIBLE);
Fragment f;
String tag;
boolean addToBackStack = true;
if (s instanceof MailboxPairingState.QrCodeReceived) {
// ignore, showing yet another progress fragment messes with back stack
return;
} else if (s instanceof MailboxPairingState.Pairing) {
f = new MailboxConnectingFragment();
tag = MailboxConnectingFragment.TAG;
addToBackStack = false;
} else if (s instanceof MailboxPairingState.InvalidQrCode) {
f = ErrorFragment.newInstance(
R.string.mailbox_setup_qr_code_wrong_title,
R.string.mailbox_setup_qr_code_wrong_description);
tag = ErrorFragment.TAG;
} else if (s instanceof MailboxPairingState.MailboxAlreadyPaired) {
// TODO
Toast.makeText(this, "MailboxAlreadyPaired", LENGTH_LONG).show();
return;
} else if (s instanceof MailboxPairingState.ConnectionError) {
// TODO
Toast.makeText(this, "Connection Error", LENGTH_LONG).show();
return;
} else if (s instanceof MailboxPairingState.AssertionError) {
// TODO
Toast.makeText(this, "Connection Error", LENGTH_LONG).show();
return;
} else if (s instanceof MailboxPairingState.Paired) {
// TODO
Toast.makeText(this, "Connection Error", LENGTH_LONG).show();
return;
} else {
throw new IllegalStateException("Unhandled state: " + s.getClass());
}
showFragment(getSupportFragmentManager(), f, tag, addToBackStack);
}
private void onOffline() {
@@ -120,9 +150,10 @@ public class MailboxActivity extends BriarActivity {
OfflineFragment.TAG);
}
private void onIsSetup(MailboxStatus mailboxStatus) {
private void onIsPaired(MailboxStatus mailboxStatus) {
progressBar.setVisibility(INVISIBLE);
// TODO
Toast.makeText(this, "NOT IMPLEMENTED", Toast.LENGTH_LONG).show();
Toast.makeText(this, "NOT IMPLEMENTED", LENGTH_LONG).show();
}
}

View File

@@ -1,6 +1,6 @@
package org.briarproject.briar.android.mailbox;
import org.briarproject.bramble.api.mailbox.MailboxProperties;
import org.briarproject.bramble.api.mailbox.MailboxPairingState;
import org.briarproject.bramble.api.mailbox.MailboxStatus;
import androidx.annotation.Nullable;
@@ -13,29 +13,31 @@ class MailboxState {
static class ScanningQrCode extends MailboxState {
}
static class SettingUp extends MailboxState {
static class Pairing extends MailboxState {
final MailboxPairingState pairingState;
Pairing(MailboxPairingState pairingState) {
this.pairingState = pairingState;
}
}
static class QrCodeWrong extends MailboxState {
}
static class OfflineInSetup extends MailboxState {
static class OfflineWhenPairing extends MailboxState {
@Nullable
final MailboxProperties mailboxProperties;
final String qrCodePayload;
OfflineInSetup(@Nullable MailboxProperties mailboxProperties) {
this.mailboxProperties = mailboxProperties;
OfflineWhenPairing(@Nullable String qrCodePayload) {
this.qrCodePayload = qrCodePayload;
}
OfflineInSetup() {
OfflineWhenPairing() {
this(null);
}
}
static class IsSetup extends MailboxState {
static class IsPaired extends MailboxState {
final MailboxStatus mailboxStatus;
IsSetup(MailboxStatus mailboxStatus) {
IsPaired(MailboxStatus mailboxStatus) {
this.mailboxStatus = mailboxStatus;
}
}

View File

@@ -4,15 +4,14 @@ import android.app.Application;
import com.google.zxing.Result;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.Consumer;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.mailbox.MailboxAuthToken;
import org.briarproject.bramble.api.mailbox.MailboxProperties;
import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
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.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin;
@@ -25,38 +24,34 @@ import org.briarproject.briar.android.viewmodel.DbViewModel;
import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.inject.Inject;
import androidx.annotation.AnyThread;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
@NotNullByDefault
class MailboxViewModel extends DbViewModel
implements QrCodeDecoder.ResultCallback {
implements QrCodeDecoder.ResultCallback, Consumer<MailboxPairingState> {
private static final Logger LOG =
getLogger(MailboxViewModel.class.getName());
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
private static final int VERSION_REQUIRED = 32;
private final CryptoComponent crypto;
private final QrCodeDecoder qrCodeDecoder;
private final PluginManager pluginManager;
private final MailboxSettingsManager mailboxSettingsManager;
private final MailboxManager mailboxManager;
private final MutableLiveEvent<MailboxState> state =
new MutableLiveEvent<>();
@Nullable
private MailboxPairingTask pairingTask = null;
@Inject
MailboxViewModel(
@@ -66,29 +61,43 @@ class MailboxViewModel extends DbViewModel
TransactionManager db,
AndroidExecutor androidExecutor,
@IoExecutor Executor ioExecutor,
CryptoComponent crypto,
PluginManager pluginManager,
MailboxSettingsManager mailboxSettingsManager) {
MailboxManager mailboxManager) {
super(app, dbExecutor, lifecycleManager, db, androidExecutor);
this.crypto = crypto;
this.pluginManager = pluginManager;
this.mailboxSettingsManager = mailboxSettingsManager;
this.mailboxManager = mailboxManager;
qrCodeDecoder = new QrCodeDecoder(androidExecutor, ioExecutor, this);
checkIfSetup();
}
@Override
protected void onCleared() {
super.onCleared();
MailboxPairingTask task = pairingTask;
if (task != null) {
task.removeObserver(this);
pairingTask = null;
}
}
@UiThread
private void checkIfSetup() {
runOnDbThread(true, txn -> {
MailboxProperties props =
mailboxSettingsManager.getOwnMailboxProperties(txn);
if (props == null) state.postEvent(new NotSetup());
else {
MailboxStatus mailboxStatus =
mailboxSettingsManager.getOwnMailboxStatus(txn);
state.postEvent(new MailboxState.IsSetup(mailboxStatus));
}
}, this::handleException);
MailboxPairingTask task = mailboxManager.getCurrentPairingTask();
if (task == null) {
runOnDbThread(true, txn -> {
boolean isPaired = mailboxManager.isPaired(txn);
if (isPaired) {
MailboxStatus mailboxStatus =
mailboxManager.getMailboxStatus(txn);
state.postEvent(new MailboxState.IsPaired(mailboxStatus));
} else {
state.postEvent(new NotSetup());
}
}, this::handleException);
} else {
task.addObserver(this);
pairingTask = task;
}
}
@UiThread
@@ -96,7 +105,7 @@ class MailboxViewModel extends DbViewModel
if (isTorActive()) {
state.setEvent(new MailboxState.ScanningQrCode());
} else {
state.setEvent(new MailboxState.OfflineInSetup());
state.setEvent(new MailboxState.OfflineWhenPairing());
}
}
@@ -104,53 +113,25 @@ class MailboxViewModel extends DbViewModel
@IoExecutor
public void onQrCodeDecoded(Result result) {
LOG.info("Got result from decoder");
MailboxProperties properties;
try {
properties = decodeQrCode(result.getText());
} catch (FormatException e) {
state.postEvent(new MailboxState.QrCodeWrong());
return;
}
onMailboxPropertiesReceived(properties);
onQrCodePayloadReceived(result.getText());
}
@IoExecutor
// TODO move this into core #2168
private MailboxProperties decodeQrCode(String payload)
throws FormatException {
byte[] bytes = payload.getBytes(ISO_8859_1);
if (bytes.length != 65) {
if (LOG.isLoggable(WARNING)) {
LOG.warning("QR code length is not 65: " + bytes.length);
}
throw new FormatException();
}
int version = bytes[0] & 0xFF;
if (version != VERSION_REQUIRED) {
if (LOG.isLoggable(WARNING)) {
LOG.warning("QR code has not version " + VERSION_REQUIRED +
": " + version);
}
throw new FormatException();
}
LOG.info("QR code is valid");
byte[] onionPubKey = Arrays.copyOfRange(bytes, 1, 33);
String onionAddress = crypto.encodeOnionAddress(onionPubKey);
byte[] tokenBytes = Arrays.copyOfRange(bytes, 33, 65);
MailboxAuthToken setupToken = new MailboxAuthToken(tokenBytes);
return new MailboxProperties(onionAddress, setupToken, true);
}
private void onMailboxPropertiesReceived(MailboxProperties properties) {
@AnyThread
private void onQrCodePayloadReceived(String qrCodePayload) {
if (isTorActive()) {
// TODO pass props to core #2168
state.postEvent(new MailboxState.SettingUp());
pairingTask = mailboxManager.startPairingTask(qrCodePayload);
pairingTask.addObserver(this);
} else {
state.postEvent(new MailboxState.OfflineInSetup(properties));
state.postEvent(new MailboxState.OfflineWhenPairing(qrCodePayload));
}
}
// TODO ideally also move this into core #2168
@UiThread
@Override
public void accept(MailboxPairingState mailboxPairingState) {
state.setEvent(new MailboxState.Pairing(mailboxPairingState));
}
private boolean isTorActive() {
Plugin plugin = pluginManager.getPlugin(TorConstants.ID);
return plugin != null && plugin.getState() == ACTIVE;
@@ -158,13 +139,13 @@ class MailboxViewModel extends DbViewModel
@UiThread
void tryAgainWhenOffline() {
MailboxState.OfflineInSetup offline =
(MailboxState.OfflineInSetup) requireNonNull(
MailboxState.OfflineWhenPairing offline =
(MailboxState.OfflineWhenPairing) requireNonNull(
state.getLastValue());
if (offline.mailboxProperties == null) {
if (offline.qrCodePayload == null) {
onScanButtonClicked();
} else {
onMailboxPropertiesReceived(offline.mailboxProperties);
onQrCodePayloadReceived(offline.qrCodePayload);
}
}