diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml index 693af657f..87d431f37 100644 --- a/briar-android/src/main/AndroidManifest.xml +++ b/briar-android/src/main/AndroidManifest.xml @@ -342,7 +342,7 @@ diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java index 08057a229..05166d043 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java @@ -31,7 +31,7 @@ import org.briarproject.briar.android.account.DozeHelperModule; import org.briarproject.briar.android.account.LockManagerImpl; import org.briarproject.briar.android.account.SetupModule; import org.briarproject.briar.android.contact.ContactListModule; -import org.briarproject.briar.android.contact.add.nearby.ContactExchangeModule; +import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactModule; import org.briarproject.briar.android.forum.ForumModule; import org.briarproject.briar.android.introduction.IntroductionModule; import org.briarproject.briar.android.logging.LoggingModule; @@ -75,7 +75,7 @@ import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD; @Module(includes = { SetupModule.class, DozeHelperModule.class, - ContactExchangeModule.class, + AddNearbyContactModule.class, LoggingModule.class, LoginModule.class, NavDrawerModule.class, diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java index 18a9d26f8..1ce77a0ca 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java @@ -21,11 +21,10 @@ import org.briarproject.briar.android.blog.RssFeedImportActivity; import org.briarproject.briar.android.blog.RssFeedManageActivity; import org.briarproject.briar.android.blog.WriteBlogPostActivity; import org.briarproject.briar.android.contact.ContactListFragment; -import org.briarproject.briar.android.contact.add.nearby.ContactExchangeActivity; -import org.briarproject.briar.android.contact.add.nearby.ContactExchangeErrorFragment; -import org.briarproject.briar.android.contact.add.nearby.IntroFragment; -import org.briarproject.briar.android.contact.add.nearby.KeyAgreementActivity; -import org.briarproject.briar.android.contact.add.nearby.KeyAgreementFragment; +import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactActivity; +import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactErrorFragment; +import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactFragment; +import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactIntroFragment; import org.briarproject.briar.android.contact.add.remote.AddContactActivity; import org.briarproject.briar.android.contact.add.remote.LinkExchangeFragment; import org.briarproject.briar.android.contact.add.remote.NicknameFragment; @@ -109,9 +108,7 @@ public interface ActivityComponent { void inject(PanicPreferencesActivity activity); - void inject(ContactExchangeActivity activity); - - void inject(KeyAgreementActivity activity); + void inject(AddNearbyContactActivity activity); void inject(ConversationActivity activity); @@ -209,9 +206,9 @@ public interface ActivityComponent { void inject(FeedFragment fragment); - void inject(IntroFragment fragment); - - void inject(KeyAgreementFragment fragment); + void inject(AddNearbyContactIntroFragment fragment); + + void inject(AddNearbyContactFragment fragment); void inject(LinkExchangeFragment fragment); @@ -229,7 +226,7 @@ public interface ActivityComponent { void inject(ScreenFilterDialogFragment fragment); - void inject(ContactExchangeErrorFragment fragment); + void inject(AddNearbyContactErrorFragment fragment); void inject(AliasDialogFragment aliasDialogFragment); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java index 48c3935ae..380deb968 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java @@ -15,11 +15,11 @@ 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.contact.add.nearby.AddNearbyContactActivity; import org.briarproject.briar.android.contact.add.remote.AddContactActivity; import org.briarproject.briar.android.contact.add.remote.PendingContactListActivity; import org.briarproject.briar.android.conversation.ConversationActivity; import org.briarproject.briar.android.fragment.BaseFragment; -import org.briarproject.briar.android.contact.add.nearby.ContactExchangeActivity; import org.briarproject.briar.android.util.BriarSnackbarBuilder; import org.briarproject.briar.android.view.BriarRecyclerView; @@ -125,7 +125,8 @@ public class ContactListFragment extends BaseFragment switch (itemId) { case R.id.action_add_contact_nearby: Intent intent = - new Intent(getContext(), ContactExchangeActivity.class); + new Intent(getContext(), + AddNearbyContactActivity.class); startActivity(intent); return; case R.id.action_add_contact_remotely: diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddContactState.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddContactState.java new file mode 100644 index 000000000..df56be6bb --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddContactState.java @@ -0,0 +1,76 @@ +package org.briarproject.briar.android.contact.add.nearby; + +import android.graphics.Bitmap; + +import org.briarproject.bramble.api.identity.Author; + +import androidx.annotation.Nullable; + +abstract class AddContactState { + + static class KeyAgreementListening extends AddContactState { + final Bitmap qrCode; + + KeyAgreementListening(Bitmap qrCode) { + this.qrCode = qrCode; + } + } + + static class QrCodeScanned extends AddContactState { + } + + static class KeyAgreementWaiting extends AddContactState { + } + + static class KeyAgreementStarted extends AddContactState { + } + + static class ContactExchangeStarted extends AddContactState { + } + + static class ContactExchangeFinished extends AddContactState { + final ContactExchangeResult result; + + ContactExchangeFinished(ContactExchangeResult result) { + this.result = result; + } + } + + static class Failed extends AddContactState { + /** + * Non-null if failed due to the scanned QR code version. + * True if the app producing the code is too old. + * False if the scanning app is too old. + */ + @Nullable + final Boolean qrCodeTooOld; + + Failed(@Nullable Boolean qrCodeTooOld) { + this.qrCodeTooOld = qrCodeTooOld; + } + + Failed() { + this(null); + } + } + + abstract static class ContactExchangeResult { + static class Success extends ContactExchangeResult { + final Author remoteAuthor; + + Success(Author remoteAuthor) { + this.remoteAuthor = remoteAuthor; + } + } + + static class Error extends ContactExchangeResult { + @Nullable + final Author duplicateAuthor; + + Error(@Nullable Author duplicateAuthor) { + this.duplicateAuthor = duplicateAuthor; + } + } + } // end ContactExchangeResult + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/KeyAgreementActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java similarity index 63% rename from briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/KeyAgreementActivity.java rename to briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java index 6c8b76a41..eb56baeeb 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/KeyAgreementActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactActivity.java @@ -6,13 +6,19 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.MenuItem; +import android.widget.Toast; +import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.NullSafety; 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.contact.add.nearby.ContactExchangeViewModel.BluetoothDecision; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeFinished; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed; +import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; @@ -21,32 +27,32 @@ import java.util.logging.Logger; import javax.annotation.Nullable; import javax.inject.Inject; -import androidx.annotation.UiThread; import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.ViewModelProvider; import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE; import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED; +import static android.widget.Toast.LENGTH_LONG; +import static java.util.Objects.requireNonNull; import static java.util.logging.Logger.getLogger; -import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull; import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_BLUETOOTH_DISCOVERABLE; -import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.BluetoothDecision.ACCEPTED; -import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.BluetoothDecision.REFUSED; -import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.BluetoothDecision.UNKNOWN; +import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.ACCEPTED; +import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED; +import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.UNKNOWN; @MethodsNotNullByDefault @ParametersNotNullByDefault -public abstract class KeyAgreementActivity extends BriarActivity +public class AddNearbyContactActivity extends BriarActivity implements BaseFragmentListener { private static final Logger LOG = - getLogger(KeyAgreementActivity.class.getName()); + getLogger(AddNearbyContactActivity.class.getName()); @Inject ViewModelProvider.Factory viewModelFactory; - protected ContactExchangeViewModel viewModel; + private AddNearbyContactViewModel viewModel; private AddNearbyContactPermissionManager permissionManager; /** @@ -62,7 +68,7 @@ public abstract class KeyAgreementActivity extends BriarActivity public void injectActivity(ActivityComponent component) { component.inject(this); viewModel = new ViewModelProvider(this, viewModelFactory) - .get(ContactExchangeViewModel.class); + .get(AddNearbyContactViewModel.class); permissionManager = new AddNearbyContactPermissionManager(this, viewModel.isBluetoothSupported()); } @@ -73,9 +79,10 @@ public abstract class KeyAgreementActivity extends BriarActivity setContentView(R.layout.activity_fragment_container_toolbar); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); - requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); + NullSafety.requireNonNull(getSupportActionBar()) + .setDisplayHomeAsUpEnabled(true); if (state == null) { - showInitialFragment(IntroFragment.newInstance()); + showInitialFragment(AddNearbyContactIntroFragment.newInstance()); } IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED); bluetoothReceiver = new BluetoothStateReceiver(); @@ -90,6 +97,10 @@ public abstract class KeyAgreementActivity extends BriarActivity viewModel.getShowQrCodeFragment().observeEvent(this, show -> { if (show) showQrCodeFragment(); }); + requireNonNull(getSupportActionBar()) + .setTitle(R.string.add_contact_title); + viewModel.getState() + .observe(this, this::onAddContactStateChanged); } @Override @@ -120,15 +131,6 @@ public abstract class KeyAgreementActivity extends BriarActivity if (bluetoothReceiver != null) unregisterReceiver(bluetoothReceiver); } - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - @Override public void onActivityResult(int request, int result, @Nullable Intent data) { @@ -145,7 +147,15 @@ public abstract class KeyAgreementActivity extends BriarActivity } @Override - @UiThread + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, @@ -154,6 +164,16 @@ public abstract class KeyAgreementActivity extends BriarActivity grantResults, this::showQrCodeFragmentIfAllowed); } + @Override + public void onBackPressed() { + if (viewModel.getState().getValue() instanceof Failed) { + // finish this activity when going back in failed state + supportFinishAfterTransition(); + } else { + super.onBackPressed(); + } + } + private void requestBluetoothDiscoverable() { if (!viewModel.isBluetoothSupported()) { viewModel.bluetoothDecision = BluetoothDecision.NO_ADAPTER; @@ -174,7 +194,8 @@ public abstract class KeyAgreementActivity extends BriarActivity @SuppressWarnings("StatementWithEmptyBody") private void showQrCodeFragmentIfAllowed() { boolean continueClicked = // never set to null - requireNonNull(viewModel.getWasContinueClicked().getValue()); + NullSafety.requireNonNull( + viewModel.getWasContinueClicked().getValue()); boolean permissionsGranted = permissionManager.areEssentialPermissionsGranted(); if (isResumed && continueClicked && permissionsGranted) { @@ -197,8 +218,8 @@ public abstract class KeyAgreementActivity extends BriarActivity private void showQrCodeFragment() { // FIXME #824 FragmentManager fm = getSupportFragmentManager(); - if (fm.findFragmentByTag(KeyAgreementFragment.TAG) == null) { - BaseFragment f = KeyAgreementFragment.newInstance(); + if (fm.findFragmentByTag(AddNearbyContactFragment.TAG) == null) { + BaseFragment f = AddNearbyContactFragment.newInstance(); fm.beginTransaction() .replace(R.id.fragmentContainer, f, f.getUniqueTag()) .addToBackStack(f.getUniqueTag()) @@ -206,6 +227,65 @@ public abstract class KeyAgreementActivity extends BriarActivity } } + private void onAddContactStateChanged(AddContactState state) { + if (state instanceof ContactExchangeFinished) { + ContactExchangeResult result = + ((ContactExchangeFinished) state).result; + onContactExchangeResult(result); + } else if (state instanceof Failed) { + // Remove navigation icon, so user can't go back when failed + // ErrorFragment will finish or relaunch this activity + Toolbar toolbar = findViewById(R.id.toolbar); + toolbar.setNavigationIcon(null); + + Boolean qrCodeTooOld = ((Failed) state).qrCodeTooOld; + onAddingContactFailed(qrCodeTooOld); + } + } + + private void onContactExchangeResult(ContactExchangeResult result) { + if (result instanceof ContactExchangeResult.Success) { + Author remoteAuthor = + ((ContactExchangeResult.Success) result).remoteAuthor; + String contactName = remoteAuthor.getName(); + String text = getString(R.string.contact_added_toast, contactName); + Toast.makeText(this, text, LENGTH_LONG).show(); + supportFinishAfterTransition(); + } else if (result instanceof ContactExchangeResult.Error) { + Author duplicateAuthor = + ((ContactExchangeResult.Error) result).duplicateAuthor; + if (duplicateAuthor == null) { + showErrorFragment(); + } else { + String contactName = duplicateAuthor.getName(); + String text = + getString(R.string.contact_already_exists, contactName); + Toast.makeText(this, text, LENGTH_LONG).show(); + supportFinishAfterTransition(); + } + } else throw new AssertionError(); + } + + private void onAddingContactFailed(@Nullable Boolean qrCodeTooOld) { + if (qrCodeTooOld == null) { + showErrorFragment(); + } else { + String msg; + if (qrCodeTooOld) { + msg = getString(R.string.qr_code_too_old, + getString(R.string.app_name)); + } else { + msg = getString(R.string.qr_code_too_new, + getString(R.string.app_name)); + } + showNextFragment(AddNearbyContactErrorFragment.newInstance(msg)); + } + } + + private void showErrorFragment() { + showNextFragment(new AddNearbyContactErrorFragment()); + } + private class BluetoothStateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeErrorFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactErrorFragment.java similarity index 88% rename from briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeErrorFragment.java rename to briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactErrorFragment.java index 6a73ed8a8..15dc04848 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeErrorFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactErrorFragment.java @@ -24,14 +24,14 @@ import static org.briarproject.briar.android.util.UiUtils.onSingleLinkClick; @MethodsNotNullByDefault @ParametersNotNullByDefault -public class ContactExchangeErrorFragment extends BaseFragment { +public class AddNearbyContactErrorFragment extends BaseFragment { public static final String TAG = - ContactExchangeErrorFragment.class.getName(); + AddNearbyContactErrorFragment.class.getName(); private static final String ERROR_MSG = "errorMessage"; - public static ContactExchangeErrorFragment newInstance(String errorMsg) { - ContactExchangeErrorFragment f = new ContactExchangeErrorFragment(); + public static AddNearbyContactErrorFragment newInstance(String errorMsg) { + AddNearbyContactErrorFragment f = new AddNearbyContactErrorFragment(); Bundle args = new Bundle(); args.putString(ERROR_MSG, errorMsg); f.setArguments(args); @@ -72,7 +72,7 @@ public class ContactExchangeErrorFragment extends BaseFragment { tryAgain.setOnClickListener(view -> { // Recreate the activity so we return to the intro fragment FragmentActivity activity = requireActivity(); - Intent i = new Intent(activity, ContactExchangeActivity.class); + Intent i = new Intent(activity, AddNearbyContactActivity.class); i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); activity.startActivity(i); }); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/KeyAgreementFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactFragment.java similarity index 84% rename from briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/KeyAgreementFragment.java rename to briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactFragment.java index 2aa53fd50..c08a8cdc9 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/KeyAgreementFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactFragment.java @@ -14,11 +14,11 @@ 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.contact.add.nearby.ContactAddingState.ContactExchangeStarted; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.Failed; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementStarted; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementWaiting; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.QrCodeScanned; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeStarted; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementStarted; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementWaiting; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.QrCodeScanned; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.view.QrCodeView; @@ -42,26 +42,26 @@ import static org.briarproject.bramble.util.LogUtils.logException; @MethodsNotNullByDefault @ParametersNotNullByDefault -public class KeyAgreementFragment extends BaseFragment +public class AddNearbyContactFragment extends BaseFragment implements QrCodeView.FullscreenListener { - static final String TAG = KeyAgreementFragment.class.getName(); + static final String TAG = AddNearbyContactFragment.class.getName(); private static final Logger LOG = Logger.getLogger(TAG); @Inject ViewModelProvider.Factory viewModelFactory; - private ContactExchangeViewModel viewModel; + private AddNearbyContactViewModel viewModel; private CameraView cameraView; private LinearLayout cameraOverlay; private View statusView; private QrCodeView qrCodeView; private TextView status; - public static KeyAgreementFragment newInstance() { + public static AddNearbyContactFragment newInstance() { Bundle args = new Bundle(); - KeyAgreementFragment fragment = new KeyAgreementFragment(); + AddNearbyContactFragment fragment = new AddNearbyContactFragment(); fragment.setArguments(args); return fragment; } @@ -70,7 +70,7 @@ public class KeyAgreementFragment extends BaseFragment public void injectFragment(ActivityComponent component) { component.inject(this); viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) - .get(ContactExchangeViewModel.class); + .get(AddNearbyContactViewModel.class); } @Nullable @@ -93,7 +93,7 @@ public class KeyAgreementFragment extends BaseFragment qrCodeView.setFullscreenListener(this); viewModel.getState().observe(getViewLifecycleOwner(), - this::onContactAddingStateChanged); + this::onAddContactStateChanged); } @Override @@ -153,10 +153,10 @@ public class KeyAgreementFragment extends BaseFragment } @UiThread - private void onContactAddingStateChanged(ContactAddingState state) { - if (state instanceof ContactAddingState.KeyAgreementListening) { + private void onAddContactStateChanged(AddContactState state) { + if (state instanceof AddContactState.KeyAgreementListening) { Bitmap qrCode = - ((ContactAddingState.KeyAgreementListening) state).qrCode; + ((AddContactState.KeyAgreementListening) state).qrCode; qrCodeView.setQrCode(qrCode); } else if (state instanceof QrCodeScanned) { try { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/IntroFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactIntroFragment.java similarity index 81% rename from briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/IntroFragment.java rename to briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactIntroFragment.java index 4b7a6201f..7bc666550 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/IntroFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactIntroFragment.java @@ -21,20 +21,21 @@ import static android.view.View.FOCUS_DOWN; @MethodsNotNullByDefault @ParametersNotNullByDefault -public class IntroFragment extends BaseFragment { +public class AddNearbyContactIntroFragment extends BaseFragment { - public static final String TAG = IntroFragment.class.getName(); + public static final String TAG = AddNearbyContactIntroFragment.class.getName(); @Inject ViewModelProvider.Factory viewModelFactory; - private ContactExchangeViewModel viewModel; + private AddNearbyContactViewModel viewModel; private ScrollView scrollView; - public static IntroFragment newInstance() { + public static AddNearbyContactIntroFragment newInstance() { Bundle args = new Bundle(); - IntroFragment fragment = new IntroFragment(); + AddNearbyContactIntroFragment + fragment = new AddNearbyContactIntroFragment(); fragment.setArguments(args); return fragment; } @@ -43,7 +44,7 @@ public class IntroFragment extends BaseFragment { public void injectFragment(ActivityComponent component) { component.inject(this); viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) - .get(ContactExchangeViewModel.class); + .get(AddNearbyContactViewModel.class); } @Nullable diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeModule.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactModule.java similarity index 67% rename from briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeModule.java rename to briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactModule.java index bdd7fd2ee..79dfaa69c 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeModule.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactModule.java @@ -8,12 +8,12 @@ import dagger.Module; import dagger.multibindings.IntoMap; @Module -public abstract class ContactExchangeModule { +public abstract class AddNearbyContactModule { @Binds @IntoMap - @ViewModelKey(ContactExchangeViewModel.class) + @ViewModelKey(AddNearbyContactViewModel.class) abstract ViewModel bindContactExchangeViewModel( - ContactExchangeViewModel contactExchangeViewModel); + AddNearbyContactViewModel addNearbyContactViewModel); } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactViewModel.java similarity index 91% rename from briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeViewModel.java rename to briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactViewModel.java index 0b0d11ec2..f5f9da9ee 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeViewModel.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/AddNearbyContactViewModel.java @@ -40,13 +40,13 @@ import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.event.TransportStateEvent; import org.briarproject.briar.R; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.ContactExchangeFinished; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.ContactExchangeStarted; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementListening; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementStarted; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementWaiting; -import org.briarproject.briar.android.contact.add.nearby.ContactExchangeResult.Error; -import org.briarproject.briar.android.contact.add.nearby.ContactExchangeResult.Success; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeFinished; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Error; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Success; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeStarted; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementListening; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementStarted; +import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementWaiting; import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.MutableLiveEvent; @@ -75,15 +75,15 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING; import static org.briarproject.bramble.util.LogUtils.logException; -import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.BluetoothDecision.REFUSED; -import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.BluetoothDecision.UNKNOWN; +import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.REFUSED; +import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.BluetoothDecision.UNKNOWN; @NotNullByDefault -class ContactExchangeViewModel extends AndroidViewModel +class AddNearbyContactViewModel extends AndroidViewModel implements EventListener, QrCodeDecoder.ResultCallback { private static final Logger LOG = - getLogger(ContactExchangeViewModel.class.getName()); + getLogger(AddNearbyContactViewModel.class.getName()); enum BluetoothDecision { /** @@ -135,7 +135,7 @@ class ContactExchangeViewModel extends AndroidViewModel new MutableLiveEvent<>(); private final MutableLiveEvent transportStateChanged = new MutableLiveEvent<>(); - private final MutableLiveData state = + private final MutableLiveData state = new MutableLiveData<>(); final QrCodeDecoder qrCodeDecoder; @@ -164,7 +164,7 @@ class ContactExchangeViewModel extends AndroidViewModel private volatile boolean gotLocalPayload = false, gotRemotePayload = false; @Inject - ContactExchangeViewModel(Application app, + AddNearbyContactViewModel(Application app, EventBus eventBus, @IoExecutor Executor ioExecutor, PluginManager pluginManager, @@ -336,11 +336,11 @@ class ContactExchangeViewModel extends AndroidViewModel } else if (e instanceof KeyAgreementAbortedEvent) { LOG.info("KeyAgreementAbortedEvent received"); resetPayloadFlags(); - state.setValue(new ContactAddingState.Failed()); + state.setValue(new AddContactState.Failed()); } else if (e instanceof KeyAgreementFailedEvent) { LOG.info("KeyAgreementFailedEvent received"); resetPayloadFlags(); - state.setValue(new ContactAddingState.Failed()); + state.setValue(new AddContactState.Failed()); } } @@ -377,16 +377,16 @@ class ContactExchangeViewModel extends AndroidViewModel Payload remotePayload = payloadParser.parse(payloadBytes); gotRemotePayload = true; requireNonNull(task).connectAndRunProtocol(remotePayload); - state.postValue(new ContactAddingState.QrCodeScanned()); + state.postValue(new AddContactState.QrCodeScanned()); } catch (UnsupportedVersionException e) { resetPayloadFlags(); - state.postValue(new ContactAddingState.Failed(e.isTooOld())); + state.postValue(new AddContactState.Failed(e.isTooOld())); } catch (IOException | IllegalArgumentException e) { LOG.log(WARNING, "QR Code Invalid", e); Toast.makeText(getApplication(), R.string.qr_code_invalid, LENGTH_LONG).show(); resetPayloadFlags(); - state.postValue(new ContactAddingState.Failed()); + state.postValue(new AddContactState.Failed()); } } @@ -448,7 +448,7 @@ class ContactExchangeViewModel extends AndroidViewModel return showQrCodeFragment; } - LiveData getState() { + LiveData getState() { return state; } diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactAddingState.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactAddingState.java deleted file mode 100644 index 51278b322..000000000 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactAddingState.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.briarproject.briar.android.contact.add.nearby; - -import android.graphics.Bitmap; - -import androidx.annotation.Nullable; - -abstract class ContactAddingState { - - static class KeyAgreementListening extends ContactAddingState { - final Bitmap qrCode; - - KeyAgreementListening(Bitmap qrCode) { - this.qrCode = qrCode; - } - } - - static class QrCodeScanned extends ContactAddingState { - } - - static class KeyAgreementWaiting extends ContactAddingState { - } - - static class KeyAgreementStarted extends ContactAddingState { - } - - static class ContactExchangeStarted extends ContactAddingState { - } - - static class ContactExchangeFinished extends ContactAddingState { - final ContactExchangeResult result; - - ContactExchangeFinished(ContactExchangeResult result) { - this.result = result; - } - } - - static class Failed extends ContactAddingState { - /** - * Non-null if failed due to the scanned QR code version. - * True if the app producing the code is too old. - * False if the scanning app is too old. - */ - @Nullable - final Boolean qrCodeTooOld; - - Failed(@Nullable Boolean qrCodeTooOld) { - this.qrCodeTooOld = qrCodeTooOld; - } - - Failed() { - this(null); - } - } - -} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeActivity.java deleted file mode 100644 index c4a435136..000000000 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeActivity.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.briarproject.briar.android.contact.add.nearby; - -import android.os.Bundle; -import android.widget.Toast; - -import org.briarproject.bramble.api.identity.Author; -import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; -import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; -import org.briarproject.briar.R; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.ContactExchangeFinished; -import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.Failed; - -import javax.annotation.Nullable; - -import androidx.appcompat.widget.Toolbar; - -import static android.widget.Toast.LENGTH_LONG; -import static java.util.Objects.requireNonNull; - -@MethodsNotNullByDefault -@ParametersNotNullByDefault -public class ContactExchangeActivity extends KeyAgreementActivity { - - @Override - public void onCreate(@Nullable Bundle state) { - super.onCreate(state); - requireNonNull(getSupportActionBar()) - .setTitle(R.string.add_contact_title); - viewModel.getState() - .observe(this, this::onContactAddingStateChanged); - } - - @Override - public void onBackPressed() { - if (viewModel.getState().getValue() instanceof Failed) { - // finish this activity when going back in failed state - supportFinishAfterTransition(); - } else { - super.onBackPressed(); - } - } - - private void onContactAddingStateChanged(ContactAddingState state) { - if (state instanceof ContactExchangeFinished) { - ContactExchangeResult result = - ((ContactExchangeFinished) state).result; - onContactExchangeResult(result); - } else if (state instanceof Failed) { - // Remove navigation icon, so user can't go back when failed - // ErrorFragment will finish or relaunch this activity - Toolbar toolbar = findViewById(R.id.toolbar); - toolbar.setNavigationIcon(null); - - Boolean qrCodeTooOld = ((Failed) state).qrCodeTooOld; - onAddingContactFailed(qrCodeTooOld); - } - } - - private void onContactExchangeResult(ContactExchangeResult result) { - if (result instanceof ContactExchangeResult.Success) { - Author remoteAuthor = - ((ContactExchangeResult.Success) result).remoteAuthor; - String contactName = remoteAuthor.getName(); - String text = getString(R.string.contact_added_toast, contactName); - Toast.makeText(this, text, LENGTH_LONG).show(); - supportFinishAfterTransition(); - } else if (result instanceof ContactExchangeResult.Error) { - Author duplicateAuthor = - ((ContactExchangeResult.Error) result).duplicateAuthor; - if (duplicateAuthor == null) { - showErrorFragment(); - } else { - String contactName = duplicateAuthor.getName(); - String text = - getString(R.string.contact_already_exists, contactName); - Toast.makeText(this, text, LENGTH_LONG).show(); - supportFinishAfterTransition(); - } - } else throw new AssertionError(); - } - - private void onAddingContactFailed(@Nullable Boolean qrCodeTooOld) { - if (qrCodeTooOld == null) { - showErrorFragment(); - } else { - String msg; - if (qrCodeTooOld) { - msg = getString(R.string.qr_code_too_old, - getString(R.string.app_name)); - } else { - msg = getString(R.string.qr_code_too_new, - getString(R.string.app_name)); - } - showNextFragment(ContactExchangeErrorFragment.newInstance(msg)); - } - } - - private void showErrorFragment() { - showNextFragment(new ContactExchangeErrorFragment()); - } -} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeResult.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeResult.java deleted file mode 100644 index dad8a2a87..000000000 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/add/nearby/ContactExchangeResult.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.briarproject.briar.android.contact.add.nearby; - -import org.briarproject.bramble.api.identity.Author; -import org.briarproject.bramble.api.nullsafety.NotNullByDefault; - -import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; - -@Immutable -@NotNullByDefault -abstract class ContactExchangeResult { - - static class Success extends ContactExchangeResult { - final Author remoteAuthor; - - Success(Author remoteAuthor) { - this.remoteAuthor = remoteAuthor; - } - } - - static class Error extends ContactExchangeResult { - @Nullable - final Author duplicateAuthor; - - Error(@Nullable Author duplicateAuthor) { - this.duplicateAuthor = duplicateAuthor; - } - } - -}