From 7fad299cf0adf825bd2adc0580a3a24a5e4a77d1 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 17 Feb 2022 14:20:44 -0300 Subject: [PATCH 1/7] Add network_security_config so we are allowed to connect to onion addresses Otherwise trying to connect without TLS will throw an exception. --- briar-android/src/main/AndroidManifest.xml | 1 + briar-android/src/main/res/xml/network_security_config.xml | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 briar-android/src/main/res/xml/network_security_config.xml diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index 10559cd45..822717f27 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ android:icon="@mipmap/ic_launcher_round" android:label="@string/app_name" android:logo="@mipmap/ic_launcher_round" + android:networkSecurityConfig="@xml/network_security_config" android:supportsRtl="true" android:theme="@style/BriarTheme" tools:ignore="GoogleAppIndexingWarning,UnusedAttribute" diff --git a/briar-android/src/main/res/xml/network_security_config.xml b/briar-android/src/main/res/xml/network_security_config.xml new file mode 100644 index 000000000..a70ef7fa6 --- /dev/null +++ b/briar-android/src/main/res/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + onion + + From 80d804d2808dbace2d022485e6a2330d33148c9a Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 17 Feb 2022 14:22:56 -0300 Subject: [PATCH 2/7] 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); } } From 5e8d5c96fc29fb51cfc70bf3e65dd462617db65b Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 17 Feb 2022 15:05:00 -0300 Subject: [PATCH 3/7] Implement UI for mailbox pairing error and final states --- .../briar/android/AndroidComponent.java | 3 + .../briar/android/fragment/FinalFragment.java | 16 +++-- .../briar/android/mailbox/ErrorFragment.java | 31 +++++++-- .../android/mailbox/MailboxActivity.java | 69 +++++++++++++------ .../briar/android/mailbox/MailboxState.java | 5 ++ .../android/mailbox/MailboxViewModel.java | 16 +++++ briar-android/src/main/res/values/strings.xml | 9 +++ 7 files changed, 115 insertions(+), 34 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index e5b3d55dc..6640877e7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -44,6 +44,7 @@ import org.briarproject.briar.android.hotspot.ManualHotspotFragment; import org.briarproject.briar.android.hotspot.QrHotspotFragment; import org.briarproject.briar.android.logging.CachingLogHandler; import org.briarproject.briar.android.login.SignInReminderReceiver; +import org.briarproject.briar.android.mailbox.ErrorFragment; import org.briarproject.briar.android.mailbox.MailboxScanFragment; import org.briarproject.briar.android.mailbox.OfflineFragment; import org.briarproject.briar.android.mailbox.SetupDownloadFragment; @@ -248,4 +249,6 @@ public interface AndroidComponent void inject(MailboxScanFragment mailboxScanFragment); void inject(OfflineFragment offlineFragment); + + void inject(ErrorFragment errorFragment); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/FinalFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/FinalFragment.java index bd2f31810..daddcf4b0 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/fragment/FinalFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/FinalFragment.java @@ -63,6 +63,13 @@ public class FinalFragment extends Fragment { private NestedScrollView scrollView; protected Button buttonView; + protected final OnBackPressedCallback onBackPressedCallback = + new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + onBackButtonPressed(); + } + }; @Nullable @Override @@ -95,13 +102,8 @@ public class FinalFragment extends Fragment { AppCompatActivity a = (AppCompatActivity) requireActivity(); a.setTitle(args.getInt(ARG_TITLE)); - a.getOnBackPressedDispatcher().addCallback( - getViewLifecycleOwner(), new OnBackPressedCallback(true) { - @Override - public void handleOnBackPressed() { - onBackButtonPressed(); - } - }); + a.getOnBackPressedDispatcher() + .addCallback(getViewLifecycleOwner(), onBackPressedCallback); return v; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java index 5d43ba336..cd45c0dd7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.mailbox; +import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -10,8 +11,14 @@ import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; import org.briarproject.briar.android.fragment.FinalFragment; +import javax.inject.Inject; + import androidx.annotation.Nullable; import androidx.annotation.StringRes; +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.ViewModelProvider; + +import static org.briarproject.briar.android.AppModule.getAndroidComponent; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -29,21 +36,35 @@ public class ErrorFragment extends FinalFragment { return f; } + @Inject + ViewModelProvider.Factory viewModelFactory; + + private MailboxViewModel viewModel; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + FragmentActivity activity = requireActivity(); + getAndroidComponent(activity).inject(this); + viewModel = new ViewModelProvider(activity, viewModelFactory) + .get(MailboxViewModel.class); + } + @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = super.onCreateView(inflater, container, savedInstanceState); + onBackPressedCallback.remove(); buttonView.setText(R.string.try_again_button); + buttonView.setOnClickListener(view -> { + getParentFragmentManager().popBackStackImmediate(); + viewModel.tryAgainAfterError(); + }); return v; } - @Override - protected void onBackButtonPressed() { - requireActivity().getSupportFragmentManager().popBackStack(); - } - @Override protected boolean shouldHideActionBarBackButton() { return false; 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 bf801ad09..76ca2be4a 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 @@ -6,18 +6,19 @@ 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; import org.briarproject.briar.R; import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.BriarActivity; +import org.briarproject.briar.android.fragment.FinalFragment; import javax.inject.Inject; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import androidx.lifecycle.ViewModelProvider; import static android.view.View.INVISIBLE; @@ -84,9 +85,9 @@ public class MailboxActivity extends BriarActivity { @Override public void onBackPressed() { 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 + if (s instanceof MailboxState.Pairing) { + // don't go back in the flow if we are already pairing + // with the mailbox. We provide a try-again button instead. supportFinishAfterTransition(); } else { super.onBackPressed(); @@ -102,47 +103,63 @@ public class MailboxActivity extends BriarActivity { } private void onScanningQrCode() { - showFragment(getSupportFragmentManager(), new MailboxScanFragment(), - MailboxScanFragment.TAG); + FragmentManager fm = getSupportFragmentManager(); + if (fm.findFragmentByTag(MailboxScanFragment.TAG) != null) { + // if the scanner is already on the back stack, pop back to it + // instead of adding it to the stack again + fm.popBackStackImmediate(MailboxScanFragment.TAG, 0); + } else { + showFragment(fm, new MailboxScanFragment(), + MailboxScanFragment.TAG); + } } private void onMailboxPairingStateChanged(MailboxPairingState s) { progressBar.setVisibility(INVISIBLE); + FragmentManager fm = getSupportFragmentManager(); 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) { + if (fm.getBackStackEntryCount() == 0) { + // We re-launched into an existing state, + // need to re-populate the back stack. + repopulateBackStack(); + } 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; + f = ErrorFragment.newInstance( + R.string.mailbox_setup_already_paired_title, + R.string.mailbox_setup_already_paired_description); + tag = ErrorFragment.TAG; } 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; + f = ErrorFragment.newInstance( + R.string.mailbox_setup_io_error_title, + R.string.mailbox_setup_io_error_description); + tag = ErrorFragment.TAG; + } else if (s instanceof MailboxPairingState.UnexpectedError) { + f = ErrorFragment.newInstance( + R.string.mailbox_setup_assertion_error_title, + R.string.mailbox_setup_assertion_error_description); + tag = ErrorFragment.TAG; } else if (s instanceof MailboxPairingState.Paired) { - // TODO - Toast.makeText(this, "Connection Error", LENGTH_LONG).show(); - return; + f = FinalFragment.newInstance(R.string.mailbox_setup_paired_title, + R.drawable.ic_check_circle_outline, + R.color.briar_brand_green, + R.string.mailbox_setup_paired_description); + tag = FinalFragment.TAG; } else { throw new IllegalStateException("Unhandled state: " + s.getClass()); } - showFragment(getSupportFragmentManager(), f, tag, addToBackStack); + showFragment(fm, f, tag); } private void onOffline() { @@ -156,4 +173,12 @@ public class MailboxActivity extends BriarActivity { Toast.makeText(this, "NOT IMPLEMENTED", LENGTH_LONG).show(); } + private void repopulateBackStack() { + FragmentManager fm = getSupportFragmentManager(); + onNotSetup(); + showFragment(fm, new SetupDownloadFragment(), + SetupDownloadFragment.TAG); + onScanningQrCode(); + } + } 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 078869dfd..4e384ffa0 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 @@ -19,6 +19,11 @@ class MailboxState { Pairing(MailboxPairingState pairingState) { this.pairingState = pairingState; } + + @Nullable + String getQrCodePayload() { + return pairingState.qrCodePayload; + } } static class OfflineWhenPairing extends MailboxState { 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 5f18ad7a6..0c98a82fc 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 @@ -34,6 +34,7 @@ import androidx.annotation.Nullable; import androidx.annotation.UiThread; import static java.util.Objects.requireNonNull; +import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; @@ -129,6 +130,10 @@ class MailboxViewModel extends DbViewModel @UiThread @Override public void accept(MailboxPairingState mailboxPairingState) { + if (LOG.isLoggable(INFO)) { + LOG.info("New pairing state: " + + mailboxPairingState.getClass().getSimpleName()); + } state.setEvent(new MailboxState.Pairing(mailboxPairingState)); } @@ -149,6 +154,17 @@ class MailboxViewModel extends DbViewModel } } + @UiThread + void tryAgainAfterError() { + MailboxState.Pairing pairing = (MailboxState.Pairing) + requireNonNull(state.getLastValue()); + if (pairing.getQrCodePayload() == null) { + onScanButtonClicked(); + } else { + onQrCodePayloadReceived(pairing.getQrCodePayload()); + } + } + @UiThread QrCodeDecoder getQrCodeDecoder() { return qrCodeDecoder; diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 89ffffe0b..633188bc3 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -625,6 +625,15 @@ Connecting… Wrong QR code The scanned code is invalid. Please open the Briar Mailbox app on your mailbox device and scan the QR code it presents. + Mailbox already linked + Unlink the mailbox on your other device and try again. + Could not connect + Ensure that both devices are connected to the internet and try again. + Mailbox Error + Please send feedback (with anonymous data) via the Briar app if the issue persists. + Connected + The mailbox has been successfully linked.\n + \nFor ideal message delivery, keep the mailbox device connected to a charger and online. Offline Ensure that this device is online and connections to the internet are allowed.\n\nAfterwards, wait for the globe icon in connection settings to turn green. Check connection settings From a567301e49e3b8ff5e702d487fa38ea3e6a1866c Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 18 Feb 2022 10:54:58 -0300 Subject: [PATCH 4/7] Add a minimal MailboxStatusFragment --- .../briar/android/AndroidComponent.java | 3 + .../android/mailbox/MailboxActivity.java | 11 +-- .../mailbox/MailboxStatusFragment.java | 85 +++++++++++++++++++ .../res/layout/fragment_mailbox_status.xml | 51 +++++++++++ briar-android/src/main/res/values/strings.xml | 6 +- 5 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxStatusFragment.java create mode 100644 briar-android/src/main/res/layout/fragment_mailbox_status.xml diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index 6640877e7..ed72e1849 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -46,6 +46,7 @@ import org.briarproject.briar.android.logging.CachingLogHandler; import org.briarproject.briar.android.login.SignInReminderReceiver; import org.briarproject.briar.android.mailbox.ErrorFragment; import org.briarproject.briar.android.mailbox.MailboxScanFragment; +import org.briarproject.briar.android.mailbox.MailboxStatusFragment; import org.briarproject.briar.android.mailbox.OfflineFragment; import org.briarproject.briar.android.mailbox.SetupDownloadFragment; import org.briarproject.briar.android.removabledrive.ChooserFragment; @@ -251,4 +252,6 @@ public interface AndroidComponent void inject(OfflineFragment offlineFragment); void inject(ErrorFragment errorFragment); + + void inject(MailboxStatusFragment mailboxStatusFragment); } 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 76ca2be4a..d163a3768 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 @@ -3,10 +3,8 @@ package org.briarproject.briar.android.mailbox; import android.os.Bundle; 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.MailboxStatus; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; @@ -23,7 +21,6 @@ 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 @@ -66,7 +63,7 @@ public class MailboxActivity extends BriarActivity { } else if (state instanceof MailboxState.OfflineWhenPairing) { onOffline(); } else if (state instanceof MailboxState.IsPaired) { - onIsPaired(((MailboxState.IsPaired) state).mailboxStatus); + onIsPaired(); } else { throw new AssertionError("Unknown state: " + state); } @@ -167,10 +164,10 @@ public class MailboxActivity extends BriarActivity { OfflineFragment.TAG); } - private void onIsPaired(MailboxStatus mailboxStatus) { + private void onIsPaired() { progressBar.setVisibility(INVISIBLE); - // TODO - Toast.makeText(this, "NOT IMPLEMENTED", LENGTH_LONG).show(); + showFragment(getSupportFragmentManager(), new MailboxStatusFragment(), + MailboxStatusFragment.TAG, false); } private void repopulateBackStack() { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxStatusFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxStatusFragment.java new file mode 100644 index 000000000..9b0573a18 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxStatusFragment.java @@ -0,0 +1,85 @@ +package org.briarproject.briar.android.mailbox; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; + +import javax.inject.Inject; + +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.ViewModelProvider; + +import static java.util.Objects.requireNonNull; +import static org.briarproject.briar.android.AppModule.getAndroidComponent; +import static org.briarproject.briar.android.util.UiUtils.formatDate; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class MailboxStatusFragment extends Fragment { + + static final String TAG = MailboxStatusFragment.class.getName(); + + @Inject + ViewModelProvider.Factory viewModelFactory; + + private MailboxViewModel viewModel; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + FragmentActivity activity = requireActivity(); + getAndroidComponent(activity).inject(this); + viewModel = new ViewModelProvider(activity, viewModelFactory) + .get(MailboxViewModel.class); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_mailbox_status, + container, false); + } + + @Override + public void onViewCreated(View v, @Nullable Bundle savedInstanceState) { + super.onViewCreated(v, savedInstanceState); + MailboxState.IsPaired state = + (MailboxState.IsPaired) viewModel.getState().getLastValue(); + requireNonNull(state); // TODO check assumption + TextView statusInfoView = v.findViewById(R.id.statusInfoView); + long lastSuccess = state.mailboxStatus.getTimeOfLastSuccess(); + String lastConnectionText; + if (lastSuccess < 0) { + lastConnectionText = getString(R.string.pref_lock_timeout_never); + } else { + lastConnectionText = formatDate(requireContext(), lastSuccess); + } + String statusInfoText = getString( + R.string.mailbox_status_connected_info, lastConnectionText); + statusInfoView.setText(statusInfoText); + // TODO + // * react to status changes + // * detect problems and show them + // * update connection time periodically like conversation timestamps + // * add "Check connection" button + // * add "Unlink" button with confirmation dialog + } + + @Override + public void onStart() { + super.onStart(); + requireActivity().setTitle(R.string.mailbox_status_title); + } + +} diff --git a/briar-android/src/main/res/layout/fragment_mailbox_status.xml b/briar-android/src/main/res/layout/fragment_mailbox_status.xml new file mode 100644 index 000000000..608edd3ba --- /dev/null +++ b/briar-android/src/main/res/layout/fragment_mailbox_status.xml @@ -0,0 +1,51 @@ + + + + + + + + + + diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 633188bc3..df5962743 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -614,7 +614,7 @@ Mailbox - Mailbox Setup + Mailbox setup A Mailbox enables your contacts to send you messages while you are offline. The Mailbox will receive your messages and store them until you come online.\n \nYou can install the Briar Mailbox app on a spare device. Keep it connected to power and Wi-Fi so it\'s always online. First, install the Mailbox app on another device by searching for \"Briar Mailbox\" on Google Play or wherever you downloaded Briar.\n @@ -637,6 +637,10 @@ Offline Ensure that this device is online and connections to the internet are allowed.\n\nAfterwards, wait for the globe icon in connection settings to turn green. Check connection settings + Mailbox status + Mailbox is running + + Last connection: %s Disappearing messages From 4390c810d18b014a37464cd0aada60c7ad94b6ec Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 21 Feb 2022 14:01:32 -0300 Subject: [PATCH 5/7] Address first round of review feedback for mailbox pairing UI --- .../briar/android/mailbox/ErrorFragment.java | 1 + .../briar/android/mailbox/MailboxStatusFragment.java | 3 ++- briar-android/src/main/res/values/strings.xml | 11 +++++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java index cd45c0dd7..769f9493e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java @@ -56,6 +56,7 @@ public class ErrorFragment extends FinalFragment { @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View v = super.onCreateView(inflater, container, savedInstanceState); + // Do not hijack back button events, but let the activity process them onBackPressedCallback.remove(); buttonView.setText(R.string.try_again_button); buttonView.setOnClickListener(view -> { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxStatusFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxStatusFragment.java index 9b0573a18..378354d0e 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxStatusFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxStatusFragment.java @@ -61,7 +61,8 @@ public class MailboxStatusFragment extends Fragment { long lastSuccess = state.mailboxStatus.getTimeOfLastSuccess(); String lastConnectionText; if (lastSuccess < 0) { - lastConnectionText = getString(R.string.pref_lock_timeout_never); + lastConnectionText = + getString(R.string.mailbox_status_connected_never); } else { lastConnectionText = formatDate(requireContext(), lastSuccess); } diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index df5962743..38b7c848f 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -629,18 +629,21 @@ Unlink the mailbox on your other device and try again. Could not connect Ensure that both devices are connected to the internet and try again. - Mailbox Error + Mailbox error Please send feedback (with anonymous data) via the Briar app if the issue persists. Connected - The mailbox has been successfully linked.\n - \nFor ideal message delivery, keep the mailbox device connected to a charger and online. + Your Mailbox has been successfully linked with Briar.\n + \nKeep your Mailbox connected to power and Wi-Fi so it\'s always online. Offline - Ensure that this device is online and connections to the internet are allowed.\n\nAfterwards, wait for the globe icon in connection settings to turn green. + Ensure that this device is online and connections to the Internet are allowed.\n + \nAfterwards, wait for the globe icon in the connection settings screen to turn green. Check connection settings Mailbox status Mailbox is running Last connection: %s + + Never Disappearing messages From 952ac2c922532e2be7c8b54f09e9fe281eb6f7cf Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 22 Feb 2022 14:43:21 -0300 Subject: [PATCH 6/7] Simplify fragment transitions for mailbox pairing UI Now, trying again always starts before scanning, so the user needs to scan the code again. --- .../api/mailbox/MailboxPairingState.java | 34 ------------- .../mailbox/MailboxPairingTaskImpl.java | 8 +-- .../briar/android/AndroidComponent.java | 3 ++ .../briar/android/mailbox/ErrorFragment.java | 5 +- .../android/mailbox/MailboxActivity.java | 51 +++++++++++-------- .../android/mailbox/MailboxScanFragment.java | 2 +- .../briar/android/mailbox/MailboxState.java | 21 ++------ .../android/mailbox/MailboxViewModel.java | 30 +++-------- .../android/mailbox/OfflineFragment.java | 5 +- .../android/mailbox/SetupIntroFragment.java | 28 +++++++--- briar-android/src/main/res/values/strings.xml | 2 + 11 files changed, 76 insertions(+), 113 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java index 8581da441..8e129e2fe 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPairingState.java @@ -1,59 +1,25 @@ package org.briarproject.bramble.api.mailbox; -import javax.annotation.Nullable; - public abstract class MailboxPairingState { - /** - * The QR code payload that was scanned by the user. - * This is null if the code should not be re-used anymore in this state. - */ - @Nullable - public final String qrCodePayload; - - MailboxPairingState(@Nullable String qrCodePayload) { - this.qrCodePayload = qrCodePayload; - } - public static class QrCodeReceived extends MailboxPairingState { - public QrCodeReceived(String qrCodePayload) { - super(qrCodePayload); - } } public static class Pairing extends MailboxPairingState { - public Pairing(String qrCodePayload) { - super(qrCodePayload); - } } public static class Paired extends MailboxPairingState { - public Paired() { - super(null); - } } public static class InvalidQrCode extends MailboxPairingState { - public InvalidQrCode() { - super(null); - } } public static class MailboxAlreadyPaired extends MailboxPairingState { - public MailboxAlreadyPaired() { - super(null); - } } public static class ConnectionError extends MailboxPairingState { - public ConnectionError(String qrCodePayload) { - super(qrCodePayload); - } } public static class UnexpectedError extends MailboxPairingState { - public UnexpectedError(String qrCodePayload) { - super(qrCodePayload); - } } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java index 03f36d2f7..32ad7d727 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java @@ -71,7 +71,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask { this.clock = clock; this.api = api; this.mailboxSettingsManager = mailboxSettingsManager; - state = new MailboxPairingState.QrCodeReceived(payload); + state = new MailboxPairingState.QrCodeReceived(); } @Override @@ -100,15 +100,15 @@ class MailboxPairingTaskImpl implements MailboxPairingTask { } catch (MailboxAlreadyPairedException e) { onMailboxError(e, new MailboxPairingState.MailboxAlreadyPaired()); } catch (IOException e) { - onMailboxError(e, new MailboxPairingState.ConnectionError(payload)); + onMailboxError(e, new MailboxPairingState.ConnectionError()); } catch (ApiException | DbException e) { - onMailboxError(e, new MailboxPairingState.UnexpectedError(payload)); + onMailboxError(e, new MailboxPairingState.UnexpectedError()); } } private void pairMailbox() throws IOException, ApiException, DbException { MailboxProperties mailboxProperties = decodeQrCodePayload(payload); - setState(new MailboxPairingState.Pairing(payload)); + setState(new MailboxPairingState.Pairing()); MailboxAuthToken ownerToken = api.setup(mailboxProperties); MailboxProperties ownerProperties = new MailboxProperties( mailboxProperties.getBaseUrl(), ownerToken, true); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java index ed72e1849..0fe7c4876 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java @@ -49,6 +49,7 @@ import org.briarproject.briar.android.mailbox.MailboxScanFragment; import org.briarproject.briar.android.mailbox.MailboxStatusFragment; import org.briarproject.briar.android.mailbox.OfflineFragment; import org.briarproject.briar.android.mailbox.SetupDownloadFragment; +import org.briarproject.briar.android.mailbox.SetupIntroFragment; import org.briarproject.briar.android.removabledrive.ChooserFragment; import org.briarproject.briar.android.removabledrive.ReceiveFragment; import org.briarproject.briar.android.removabledrive.SendFragment; @@ -245,6 +246,8 @@ public interface AndroidComponent void inject(BluetoothIntroFragment bluetoothIntroFragment); + void inject(SetupIntroFragment setupIntroFragment); + void inject(SetupDownloadFragment setupDownloadFragment); void inject(MailboxScanFragment mailboxScanFragment); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java index 769f9493e..ffc37c11a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java @@ -59,10 +59,7 @@ public class ErrorFragment extends FinalFragment { // Do not hijack back button events, but let the activity process them onBackPressedCallback.remove(); buttonView.setText(R.string.try_again_button); - buttonView.setOnClickListener(view -> { - getParentFragmentManager().popBackStackImmediate(); - viewModel.tryAgainAfterError(); - }); + buttonView.setOnClickListener(view -> viewModel.showDownloadFragment()); return v; } 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 d163a3768..df58ace2d 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 @@ -54,6 +54,8 @@ public class MailboxActivity extends BriarActivity { viewModel.getState().observeEvent(this, state -> { if (state instanceof MailboxState.NotSetup) { onNotSetup(); + } else if (state instanceof MailboxState.ShowDownload) { + onShowDownload(); } else if (state instanceof MailboxState.ScanningQrCode) { onScanningQrCode(); } else if (state instanceof MailboxState.Pairing) { @@ -62,6 +64,8 @@ public class MailboxActivity extends BriarActivity { onMailboxPairingStateChanged(s); } else if (state instanceof MailboxState.OfflineWhenPairing) { onOffline(); + } else if (state instanceof MailboxState.CameraError) { + onCameraError(); } else if (state instanceof MailboxState.IsPaired) { onIsPaired(); } else { @@ -99,32 +103,38 @@ public class MailboxActivity extends BriarActivity { .commit(); } - private void onScanningQrCode() { + private void onShowDownload() { FragmentManager fm = getSupportFragmentManager(); - if (fm.findFragmentByTag(MailboxScanFragment.TAG) != null) { - // if the scanner is already on the back stack, pop back to it + if (fm.findFragmentByTag(SetupDownloadFragment.TAG) != null) { + // if the fragment is already on the back stack, pop back to it // instead of adding it to the stack again - fm.popBackStackImmediate(MailboxScanFragment.TAG, 0); + fm.popBackStackImmediate(SetupDownloadFragment.TAG, 0); } else { - showFragment(fm, new MailboxScanFragment(), - MailboxScanFragment.TAG); + showFragment(fm, new SetupDownloadFragment(), + SetupDownloadFragment.TAG); } } + private void onScanningQrCode() { + showFragment(getSupportFragmentManager(), new MailboxScanFragment(), + MailboxScanFragment.TAG); + } + private void onMailboxPairingStateChanged(MailboxPairingState s) { progressBar.setVisibility(INVISIBLE); FragmentManager fm = getSupportFragmentManager(); + if (fm.getBackStackEntryCount() == 0) { + // We re-launched into an existing state, + // need to re-populate the back stack. + onNotSetup(); + onShowDownload(); + } Fragment f; String tag; if (s instanceof MailboxPairingState.QrCodeReceived) { - // ignore, showing yet another progress fragment messes with back stack - return; + f = new MailboxConnectingFragment(); + tag = MailboxConnectingFragment.TAG; } else if (s instanceof MailboxPairingState.Pairing) { - if (fm.getBackStackEntryCount() == 0) { - // We re-launched into an existing state, - // need to re-populate the back stack. - repopulateBackStack(); - } f = new MailboxConnectingFragment(); tag = MailboxConnectingFragment.TAG; } else if (s instanceof MailboxPairingState.InvalidQrCode) { @@ -164,18 +174,17 @@ public class MailboxActivity extends BriarActivity { OfflineFragment.TAG); } + private void onCameraError() { + Fragment f = ErrorFragment.newInstance( + R.string.mailbox_setup_camera_error_title, + R.string.mailbox_setup_camera_error_description); + showFragment(getSupportFragmentManager(), f, ErrorFragment.TAG); + } + private void onIsPaired() { progressBar.setVisibility(INVISIBLE); showFragment(getSupportFragmentManager(), new MailboxStatusFragment(), MailboxStatusFragment.TAG, false); } - private void repopulateBackStack() { - FragmentManager fm = getSupportFragmentManager(); - onNotSetup(); - showFragment(fm, new SetupDownloadFragment(), - SetupDownloadFragment.TAG); - onScanningQrCode(); - } - } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxScanFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxScanFragment.java index 335fd90f8..80afa4863 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxScanFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/MailboxScanFragment.java @@ -94,7 +94,7 @@ public class MailboxScanFragment extends Fragment { logException(LOG, WARNING, e); Toast.makeText(requireContext(), R.string.camera_error, LENGTH_LONG).show(); - requireActivity().getSupportFragmentManager().popBackStack(); + viewModel.onCameraError(); } } 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 4e384ffa0..7d2ef097e 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 @@ -3,13 +3,14 @@ package org.briarproject.briar.android.mailbox; import org.briarproject.bramble.api.mailbox.MailboxPairingState; import org.briarproject.bramble.api.mailbox.MailboxStatus; -import androidx.annotation.Nullable; - class MailboxState { static class NotSetup extends MailboxState { } + static class ShowDownload extends MailboxState { + } + static class ScanningQrCode extends MailboxState { } @@ -19,24 +20,12 @@ class MailboxState { Pairing(MailboxPairingState pairingState) { this.pairingState = pairingState; } - - @Nullable - String getQrCodePayload() { - return pairingState.qrCodePayload; - } } static class OfflineWhenPairing extends MailboxState { - @Nullable - final String qrCodePayload; + } - OfflineWhenPairing(@Nullable String qrCodePayload) { - this.qrCodePayload = qrCodePayload; - } - - OfflineWhenPairing() { - this(null); - } + static class CameraError extends MailboxState { } static class IsPaired extends MailboxState { 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 0c98a82fc..2a8e15a6b 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 @@ -33,7 +33,6 @@ import androidx.annotation.AnyThread; import androidx.annotation.Nullable; import androidx.annotation.UiThread; -import static java.util.Objects.requireNonNull; import static java.util.logging.Level.INFO; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; @@ -110,6 +109,11 @@ class MailboxViewModel extends DbViewModel } } + @UiThread + void onCameraError() { + state.setEvent(new MailboxState.CameraError()); + } + @Override @IoExecutor public void onQrCodeDecoded(Result result) { @@ -123,7 +127,7 @@ class MailboxViewModel extends DbViewModel pairingTask = mailboxManager.startPairingTask(qrCodePayload); pairingTask.addObserver(this); } else { - state.postEvent(new MailboxState.OfflineWhenPairing(qrCodePayload)); + state.postEvent(new MailboxState.OfflineWhenPairing()); } } @@ -143,26 +147,8 @@ class MailboxViewModel extends DbViewModel } @UiThread - void tryAgainWhenOffline() { - MailboxState.OfflineWhenPairing offline = - (MailboxState.OfflineWhenPairing) requireNonNull( - state.getLastValue()); - if (offline.qrCodePayload == null) { - onScanButtonClicked(); - } else { - onQrCodePayloadReceived(offline.qrCodePayload); - } - } - - @UiThread - void tryAgainAfterError() { - MailboxState.Pairing pairing = (MailboxState.Pairing) - requireNonNull(state.getLastValue()); - if (pairing.getQrCodePayload() == null) { - onScanButtonClicked(); - } else { - onQrCodePayloadReceived(pairing.getQrCodePayload()); - } + void showDownloadFragment() { + state.setEvent(new MailboxState.ShowDownload()); } @UiThread diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/OfflineFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/OfflineFragment.java index fba30ccf6..99ae679be 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/OfflineFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/OfflineFragment.java @@ -62,10 +62,7 @@ public class OfflineFragment extends Fragment { startActivity(i); }); buttonView = v.findViewById(R.id.button); - buttonView.setOnClickListener(view -> { - getParentFragmentManager().popBackStackImmediate(); - viewModel.tryAgainWhenOffline(); - }); + buttonView.setOnClickListener(view -> viewModel.showDownloadFragment()); return v; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupIntroFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupIntroFragment.java index 8ba22a04c..febe902a4 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupIntroFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/SetupIntroFragment.java @@ -1,5 +1,6 @@ package org.briarproject.briar.android.mailbox; +import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -11,12 +12,15 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.briar.R; +import javax.inject.Inject; + import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.ViewModelProvider; import static android.view.View.FOCUS_DOWN; -import static org.briarproject.briar.android.util.UiUtils.showFragment; +import static org.briarproject.briar.android.AppModule.getAndroidComponent; @MethodsNotNullByDefault @ParametersNotNullByDefault @@ -24,8 +28,22 @@ public class SetupIntroFragment extends Fragment { static final String TAG = SetupIntroFragment.class.getName(); + @Inject + ViewModelProvider.Factory viewModelFactory; + + private MailboxViewModel viewModel; + private ScrollView scrollView; + @Override + public void onAttach(Context context) { + super.onAttach(context); + FragmentActivity activity = requireActivity(); + getAndroidComponent(activity).inject(this); + viewModel = new ViewModelProvider(activity, viewModelFactory) + .get(MailboxViewModel.class); + } + @Nullable @Override public View onCreateView(LayoutInflater inflater, @@ -35,11 +53,7 @@ public class SetupIntroFragment extends Fragment { container, false); scrollView = v.findViewById(R.id.scrollView); Button button = v.findViewById(R.id.continueButton); - button.setOnClickListener(view -> { - FragmentManager fm = getParentFragmentManager(); - Fragment f = new SetupDownloadFragment(); - showFragment(fm, f, SetupDownloadFragment.TAG); - }); + button.setOnClickListener(view -> viewModel.showDownloadFragment()); return v; } diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 38b7c848f..fd79a88d7 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -631,6 +631,8 @@ Ensure that both devices are connected to the internet and try again. Mailbox error Please send feedback (with anonymous data) via the Briar app if the issue persists. + @string/camera_error + Could not access camera. Try again, maybe after rebooting device. Connected Your Mailbox has been successfully linked with Briar.\n \nKeep your Mailbox connected to power and Wi-Fi so it\'s always online. From 9fa3ee18a48cf3a282e75cef94c9df84a6af6f27 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 25 Feb 2022 10:42:16 -0300 Subject: [PATCH 7/7] Capitalize more words and fix duplicate string --- .../src/main/res/layout/fragment_mailbox_setup_download.xml | 2 +- briar-android/src/main/res/values/strings.xml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/briar-android/src/main/res/layout/fragment_mailbox_setup_download.xml b/briar-android/src/main/res/layout/fragment_mailbox_setup_download.xml index a0bf77a92..c3850b4af 100644 --- a/briar-android/src/main/res/layout/fragment_mailbox_setup_download.xml +++ b/briar-android/src/main/res/layout/fragment_mailbox_setup_download.xml @@ -35,7 +35,7 @@ android:layout_marginHorizontal="@dimen/margin_xlarge" android:layout_marginTop="@dimen/margin_xlarge" android:layout_marginBottom="@dimen/margin_large" - android:text="@string/mailbox_setup_intro" + android:text="@string/mailbox_setup_download" android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" app:layout_constraintBottom_toTopOf="@+id/scanButton" app:layout_constraintEnd_toEndOf="parent" diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index fd79a88d7..318425d01 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -624,11 +624,11 @@ You have denied access to the camera, but scanning a QR code requires using the camera.\n\nPlease consider granting access. Connecting… Wrong QR code - The scanned code is invalid. Please open the Briar Mailbox app on your mailbox device and scan the QR code it presents. + The scanned code is invalid. Please open the Briar Mailbox app on your Mailbox device and scan the QR code it presents. Mailbox already linked - Unlink the mailbox on your other device and try again. + Unlink the Mailbox on your other device and try again. Could not connect - Ensure that both devices are connected to the internet and try again. + Ensure that both devices are connected to the Internet and try again. Mailbox error Please send feedback (with anonymous data) via the Briar app if the issue persists. @string/camera_error