diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java index 0c4761ada..30c518dbc 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java @@ -181,12 +181,6 @@ public abstract class BaseActivity extends AppCompatActivity showFragment(getSupportFragmentManager(), f, f.getUniqueTag()); } - protected boolean isFragmentAdded(String fragmentTag) { - FragmentManager fm = getSupportFragmentManager(); - Fragment f = fm.findFragmentByTag(fragmentTag); - return f != null && f.isAdded(); - } - private boolean showScreenFilterWarning() { if (((BriarApplication) getApplication()).isInstrumentationTest()) { return false; diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java index 359b86f2d..edbe226b7 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java @@ -56,13 +56,9 @@ public class HotspotActivity extends BriarActivity if (hotspotState instanceof HotspotStarted) { HotspotStarted started = (HotspotStarted) hotspotState; String tag = HotspotFragment.TAG; - // check if fragment is already added - // to not lose state on configuration changes - if (fm.findFragmentByTag(tag) == null) { - if (started.wasNotYetConsumed()) { - started.consume(); - showFragment(fm, new HotspotFragment(), tag); - } + if (started.wasNotYetConsumed()) { + started.consume(); + showFragment(fm, new HotspotFragment(), tag); } } else if (hotspotState instanceof HotspotError) { HotspotError error = (HotspotError) hotspotState; @@ -116,10 +112,8 @@ public class HotspotActivity extends BriarActivity private void showErrorFragment(String error) { FragmentManager fm = getSupportFragmentManager(); String tag = HotspotErrorFragment.TAG; - if (fm.findFragmentByTag(tag) == null) { - Fragment f = HotspotErrorFragment.newInstance(error); - showFragment(fm, f, tag, false); - } + Fragment f = HotspotErrorFragment.newInstance(error); + showFragment(fm, f, tag, false); } @Override diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java index c65a06cc7..6c43e0126 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java @@ -85,16 +85,10 @@ public class StartupActivity extends BaseActivity implements if (state == SIGNED_OUT) { // Configuration changes such as screen rotation // can cause this to get called again. - // Don't replace the fragment in that case to not lose view state. - if (!isFragmentAdded(PasswordFragment.TAG)) { - showInitialFragment(new PasswordFragment()); - } + showInitialFragment(new PasswordFragment()); } else if (state == SIGNED_IN || state == STARTING) { startService(new Intent(this, BriarService.class)); - // Only show OpenDatabaseFragment if not already visible. - if (!isFragmentAdded(OpenDatabaseFragment.TAG)) { - showNextFragment(new OpenDatabaseFragment()); - } + showNextFragment(new OpenDatabaseFragment()); } else if (state == STARTED) { setResult(RESULT_OK); supportFinishAfterTransition(); 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 new file mode 100644 index 000000000..e2be4c001 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/mailbox/ErrorFragment.java @@ -0,0 +1,47 @@ +package org.briarproject.briar.android.mailbox; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.briar.R; +import org.briarproject.briar.android.fragment.FinalFragment; + +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +public class ErrorFragment extends FinalFragment { + + public static ErrorFragment newInstance(@StringRes int title, + @StringRes int text) { + ErrorFragment f = new ErrorFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_TITLE, title); + args.putInt(ARG_ICON, R.drawable.alerts_and_states_error); + args.putInt(ARG_ICON_TINT, R.color.briar_red_500); + args.putInt(ARG_TEXT, text); + f.setArguments(args); + return f; + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View v = super.onCreateView(inflater, container, savedInstanceState); + buttonView.setText(R.string.try_again_button); + return v; + } + + @Override + protected void onBackButtonPressed() { + requireActivity().getSupportFragmentManager().popBackStack(); + } + +} 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 e8056dad2..53a2aebde 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 @@ -13,6 +13,7 @@ import org.briarproject.briar.android.activity.BriarActivity; import javax.inject.Inject; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import static android.view.View.INVISIBLE; @@ -49,9 +50,11 @@ public class MailboxActivity extends BriarActivity { viewModel.getState().observe(this, state -> { if (state instanceof MailboxState.NotSetup) { - if (savedInstanceState == null) onNotSetup(); + onNotSetup(); } else if (state instanceof MailboxState.SettingUp) { onCodeScanned(); + } else if (state instanceof MailboxState.QrCodeWrong) { + onQrCodeWrong(); } }); } @@ -90,4 +93,11 @@ public class MailboxActivity extends BriarActivity { 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); + } + } 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 2b9f32596..e8deb1df2 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 @@ -8,6 +8,9 @@ class MailboxState { static class SettingUp extends MailboxState { } + static class QrCodeWrong extends MailboxState { + } + // TODO add other states } 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 7a009ad69..1f4c657ff 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,6 +4,7 @@ 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.db.DatabaseExecutor; import org.briarproject.bramble.api.db.TransactionManager; @@ -28,7 +29,7 @@ import androidx.annotation.UiThread; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; -import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; @NotNullByDefault @@ -79,31 +80,39 @@ class MailboxViewModel extends DbViewModel @IoExecutor public void onQrCodeDecoded(Result result) { LOG.info("Got result from decoder"); - byte[] bytes = result.getText().getBytes(ISO_8859_1); + try { + // TODO pass props to core (maybe even do payload parsing there) + MailboxProperties properties = decodeQrCode(result.getText()); + } catch (FormatException e) { + state.postValue(new MailboxState.QrCodeWrong()); + return; + } + state.postValue(new MailboxState.SettingUp()); + } - if (LOG.isLoggable(INFO)) - LOG.info("QR code length in bytes: " + bytes.length); + private MailboxProperties decodeQrCode(String payload) + throws FormatException { + byte[] bytes = payload.getBytes(ISO_8859_1); if (bytes.length != 65) { - LOG.info("QR code has wrong length"); - return; + if (LOG.isLoggable(WARNING)) { + LOG.warning("QR code length is not 65: " + bytes.length); + } + throw new FormatException(); } - - if (LOG.isLoggable(INFO)) - LOG.info("QR code version: " + bytes[0]); - if (bytes[0] != VERSION_REQUIRED) { - LOG.info("QR code has wrong version"); - return; + 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); - MailboxProperties props = - new MailboxProperties(onionAddress, setupToken, true); - // TODO pass props to core (maybe even do payload parsing there) - state.postValue(new MailboxState.SettingUp()); + return new MailboxProperties(onionAddress, setupToken, true); } @UiThread diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java index 3c43564ae..ea6272b71 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java @@ -147,6 +147,10 @@ public class UiUtils { public static void showFragment(FragmentManager fm, Fragment f, @Nullable String tag, boolean addToBackStack) { + // don't re-add same (already added/visible) fragment again + Fragment fragment = fm.findFragmentByTag(tag); + if (fragment != null && fragment.isAdded()) return; + FragmentTransaction ta = fm.beginTransaction() .setCustomAnimations(R.anim.step_next_in, R.anim.step_previous_out, R.anim.step_previous_in, diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml index 6010f7a55..4f809233b 100644 --- a/briar-android/src/main/res/values/strings.xml +++ b/briar-android/src/main/res/values/strings.xml @@ -630,6 +630,8 @@ https://briarproject.org/apk 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 and scan the QR code it presents. Disappearing messages