From 80d804d2808dbace2d022485e6a2330d33148c9a Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 17 Feb 2022 14:22:56 -0300 Subject: [PATCH] Use new MailboxManager in Android UI --- .../android/mailbox/MailboxActivity.java | 77 +++++++---- .../briar/android/mailbox/MailboxState.java | 26 ++-- .../android/mailbox/MailboxViewModel.java | 129 ++++++++---------- 3 files changed, 123 insertions(+), 109 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxActivity.java index 9570f4740..bf801ad09 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxActivity.java @@ -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(); } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxState.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxState.java index caa6400e1..078869dfd 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxState.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxState.java @@ -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; } } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxViewModel.java index 1c199aa59..5f18ad7a6 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxViewModel.java @@ -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 { 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 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); } }