From 5e8d5c96fc29fb51cfc70bf3e65dd462617db65b Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 17 Feb 2022 15:05:00 -0300 Subject: [PATCH] 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