Merge activities for adding contact nearby

and rename related classes to consolidate names
This commit is contained in:
Torsten Grote
2021-02-04 14:31:41 -03:00
parent 700f6e05bf
commit bcc0442add
14 changed files with 245 additions and 276 deletions

View File

@@ -342,7 +342,7 @@
</activity> </activity>
<activity <activity
android:name="org.briarproject.briar.android.contact.add.nearby.ContactExchangeActivity" android:name="org.briarproject.briar.android.contact.add.nearby.AddNearbyContactActivity"
android:label="@string/add_contact_title" android:label="@string/add_contact_title"
android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity" android:parentActivityName="org.briarproject.briar.android.navdrawer.NavDrawerActivity"
android:theme="@style/BriarTheme.NoActionBar"> android:theme="@style/BriarTheme.NoActionBar">

View File

@@ -31,7 +31,7 @@ import org.briarproject.briar.android.account.DozeHelperModule;
import org.briarproject.briar.android.account.LockManagerImpl; import org.briarproject.briar.android.account.LockManagerImpl;
import org.briarproject.briar.android.account.SetupModule; import org.briarproject.briar.android.account.SetupModule;
import org.briarproject.briar.android.contact.ContactListModule; 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.forum.ForumModule;
import org.briarproject.briar.android.introduction.IntroductionModule; import org.briarproject.briar.android.introduction.IntroductionModule;
import org.briarproject.briar.android.logging.LoggingModule; import org.briarproject.briar.android.logging.LoggingModule;
@@ -75,7 +75,7 @@ import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
@Module(includes = { @Module(includes = {
SetupModule.class, SetupModule.class,
DozeHelperModule.class, DozeHelperModule.class,
ContactExchangeModule.class, AddNearbyContactModule.class,
LoggingModule.class, LoggingModule.class,
LoginModule.class, LoginModule.class,
NavDrawerModule.class, NavDrawerModule.class,

View File

@@ -21,11 +21,10 @@ import org.briarproject.briar.android.blog.RssFeedImportActivity;
import org.briarproject.briar.android.blog.RssFeedManageActivity; import org.briarproject.briar.android.blog.RssFeedManageActivity;
import org.briarproject.briar.android.blog.WriteBlogPostActivity; import org.briarproject.briar.android.blog.WriteBlogPostActivity;
import org.briarproject.briar.android.contact.ContactListFragment; import org.briarproject.briar.android.contact.ContactListFragment;
import org.briarproject.briar.android.contact.add.nearby.ContactExchangeActivity; import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactActivity;
import org.briarproject.briar.android.contact.add.nearby.ContactExchangeErrorFragment; import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactErrorFragment;
import org.briarproject.briar.android.contact.add.nearby.IntroFragment; import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactFragment;
import org.briarproject.briar.android.contact.add.nearby.KeyAgreementActivity; import org.briarproject.briar.android.contact.add.nearby.AddNearbyContactIntroFragment;
import org.briarproject.briar.android.contact.add.nearby.KeyAgreementFragment;
import org.briarproject.briar.android.contact.add.remote.AddContactActivity; 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.LinkExchangeFragment;
import org.briarproject.briar.android.contact.add.remote.NicknameFragment; import org.briarproject.briar.android.contact.add.remote.NicknameFragment;
@@ -109,9 +108,7 @@ public interface ActivityComponent {
void inject(PanicPreferencesActivity activity); void inject(PanicPreferencesActivity activity);
void inject(ContactExchangeActivity activity); void inject(AddNearbyContactActivity activity);
void inject(KeyAgreementActivity activity);
void inject(ConversationActivity activity); void inject(ConversationActivity activity);
@@ -209,9 +206,9 @@ public interface ActivityComponent {
void inject(FeedFragment fragment); void inject(FeedFragment fragment);
void inject(IntroFragment fragment); void inject(AddNearbyContactIntroFragment fragment);
void inject(KeyAgreementFragment fragment); void inject(AddNearbyContactFragment fragment);
void inject(LinkExchangeFragment fragment); void inject(LinkExchangeFragment fragment);
@@ -229,7 +226,7 @@ public interface ActivityComponent {
void inject(ScreenFilterDialogFragment fragment); void inject(ScreenFilterDialogFragment fragment);
void inject(ContactExchangeErrorFragment fragment); void inject(AddNearbyContactErrorFragment fragment);
void inject(AliasDialogFragment aliasDialogFragment); void inject(AliasDialogFragment aliasDialogFragment);

View File

@@ -15,11 +15,11 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; 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.AddContactActivity;
import org.briarproject.briar.android.contact.add.remote.PendingContactListActivity; import org.briarproject.briar.android.contact.add.remote.PendingContactListActivity;
import org.briarproject.briar.android.conversation.ConversationActivity; import org.briarproject.briar.android.conversation.ConversationActivity;
import org.briarproject.briar.android.fragment.BaseFragment; 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.util.BriarSnackbarBuilder;
import org.briarproject.briar.android.view.BriarRecyclerView; import org.briarproject.briar.android.view.BriarRecyclerView;
@@ -125,7 +125,8 @@ public class ContactListFragment extends BaseFragment
switch (itemId) { switch (itemId) {
case R.id.action_add_contact_nearby: case R.id.action_add_contact_nearby:
Intent intent = Intent intent =
new Intent(getContext(), ContactExchangeActivity.class); new Intent(getContext(),
AddNearbyContactActivity.class);
startActivity(intent); startActivity(intent);
return; return;
case R.id.action_add_contact_remotely: case R.id.action_add_contact_remotely:

View File

@@ -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
}

View File

@@ -6,13 +6,19 @@ import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.os.Bundle; import android.os.Bundle;
import android.view.MenuItem; 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.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.NullSafety;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity; 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;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
@@ -21,32 +27,32 @@ import java.util.logging.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.UiThread;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE; import static android.bluetooth.BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED; 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 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.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.AddNearbyContactViewModel.BluetoothDecision.ACCEPTED;
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.BluetoothDecision.REFUSED; import static org.briarproject.briar.android.contact.add.nearby.AddNearbyContactViewModel.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.UNKNOWN;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public abstract class KeyAgreementActivity extends BriarActivity public class AddNearbyContactActivity extends BriarActivity
implements BaseFragmentListener { implements BaseFragmentListener {
private static final Logger LOG = private static final Logger LOG =
getLogger(KeyAgreementActivity.class.getName()); getLogger(AddNearbyContactActivity.class.getName());
@Inject @Inject
ViewModelProvider.Factory viewModelFactory; ViewModelProvider.Factory viewModelFactory;
protected ContactExchangeViewModel viewModel; private AddNearbyContactViewModel viewModel;
private AddNearbyContactPermissionManager permissionManager; private AddNearbyContactPermissionManager permissionManager;
/** /**
@@ -62,7 +68,7 @@ public abstract class KeyAgreementActivity extends BriarActivity
public void injectActivity(ActivityComponent component) { public void injectActivity(ActivityComponent component) {
component.inject(this); component.inject(this);
viewModel = new ViewModelProvider(this, viewModelFactory) viewModel = new ViewModelProvider(this, viewModelFactory)
.get(ContactExchangeViewModel.class); .get(AddNearbyContactViewModel.class);
permissionManager = new AddNearbyContactPermissionManager(this, permissionManager = new AddNearbyContactPermissionManager(this,
viewModel.isBluetoothSupported()); viewModel.isBluetoothSupported());
} }
@@ -73,9 +79,10 @@ public abstract class KeyAgreementActivity extends BriarActivity
setContentView(R.layout.activity_fragment_container_toolbar); setContentView(R.layout.activity_fragment_container_toolbar);
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true); NullSafety.requireNonNull(getSupportActionBar())
.setDisplayHomeAsUpEnabled(true);
if (state == null) { if (state == null) {
showInitialFragment(IntroFragment.newInstance()); showInitialFragment(AddNearbyContactIntroFragment.newInstance());
} }
IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED); IntentFilter filter = new IntentFilter(ACTION_SCAN_MODE_CHANGED);
bluetoothReceiver = new BluetoothStateReceiver(); bluetoothReceiver = new BluetoothStateReceiver();
@@ -90,6 +97,10 @@ public abstract class KeyAgreementActivity extends BriarActivity
viewModel.getShowQrCodeFragment().observeEvent(this, show -> { viewModel.getShowQrCodeFragment().observeEvent(this, show -> {
if (show) showQrCodeFragment(); if (show) showQrCodeFragment();
}); });
requireNonNull(getSupportActionBar())
.setTitle(R.string.add_contact_title);
viewModel.getState()
.observe(this, this::onAddContactStateChanged);
} }
@Override @Override
@@ -120,15 +131,6 @@ public abstract class KeyAgreementActivity extends BriarActivity
if (bluetoothReceiver != null) unregisterReceiver(bluetoothReceiver); 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 @Override
public void onActivityResult(int request, int result, public void onActivityResult(int request, int result,
@Nullable Intent data) { @Nullable Intent data) {
@@ -145,7 +147,15 @@ public abstract class KeyAgreementActivity extends BriarActivity
} }
@Override @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, public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) { String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, super.onRequestPermissionsResult(requestCode, permissions,
@@ -154,6 +164,16 @@ public abstract class KeyAgreementActivity extends BriarActivity
grantResults, this::showQrCodeFragmentIfAllowed); 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() { private void requestBluetoothDiscoverable() {
if (!viewModel.isBluetoothSupported()) { if (!viewModel.isBluetoothSupported()) {
viewModel.bluetoothDecision = BluetoothDecision.NO_ADAPTER; viewModel.bluetoothDecision = BluetoothDecision.NO_ADAPTER;
@@ -174,7 +194,8 @@ public abstract class KeyAgreementActivity extends BriarActivity
@SuppressWarnings("StatementWithEmptyBody") @SuppressWarnings("StatementWithEmptyBody")
private void showQrCodeFragmentIfAllowed() { private void showQrCodeFragmentIfAllowed() {
boolean continueClicked = // never set to null boolean continueClicked = // never set to null
requireNonNull(viewModel.getWasContinueClicked().getValue()); NullSafety.requireNonNull(
viewModel.getWasContinueClicked().getValue());
boolean permissionsGranted = boolean permissionsGranted =
permissionManager.areEssentialPermissionsGranted(); permissionManager.areEssentialPermissionsGranted();
if (isResumed && continueClicked && permissionsGranted) { if (isResumed && continueClicked && permissionsGranted) {
@@ -197,8 +218,8 @@ public abstract class KeyAgreementActivity extends BriarActivity
private void showQrCodeFragment() { private void showQrCodeFragment() {
// FIXME #824 // FIXME #824
FragmentManager fm = getSupportFragmentManager(); FragmentManager fm = getSupportFragmentManager();
if (fm.findFragmentByTag(KeyAgreementFragment.TAG) == null) { if (fm.findFragmentByTag(AddNearbyContactFragment.TAG) == null) {
BaseFragment f = KeyAgreementFragment.newInstance(); BaseFragment f = AddNearbyContactFragment.newInstance();
fm.beginTransaction() fm.beginTransaction()
.replace(R.id.fragmentContainer, f, f.getUniqueTag()) .replace(R.id.fragmentContainer, f, f.getUniqueTag())
.addToBackStack(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 { private class BluetoothStateReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {

View File

@@ -24,14 +24,14 @@ import static org.briarproject.briar.android.util.UiUtils.onSingleLinkClick;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class ContactExchangeErrorFragment extends BaseFragment { public class AddNearbyContactErrorFragment extends BaseFragment {
public static final String TAG = public static final String TAG =
ContactExchangeErrorFragment.class.getName(); AddNearbyContactErrorFragment.class.getName();
private static final String ERROR_MSG = "errorMessage"; private static final String ERROR_MSG = "errorMessage";
public static ContactExchangeErrorFragment newInstance(String errorMsg) { public static AddNearbyContactErrorFragment newInstance(String errorMsg) {
ContactExchangeErrorFragment f = new ContactExchangeErrorFragment(); AddNearbyContactErrorFragment f = new AddNearbyContactErrorFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(ERROR_MSG, errorMsg); args.putString(ERROR_MSG, errorMsg);
f.setArguments(args); f.setArguments(args);
@@ -72,7 +72,7 @@ public class ContactExchangeErrorFragment extends BaseFragment {
tryAgain.setOnClickListener(view -> { tryAgain.setOnClickListener(view -> {
// Recreate the activity so we return to the intro fragment // Recreate the activity so we return to the intro fragment
FragmentActivity activity = requireActivity(); FragmentActivity activity = requireActivity();
Intent i = new Intent(activity, ContactExchangeActivity.class); Intent i = new Intent(activity, AddNearbyContactActivity.class);
i.setFlags(FLAG_ACTIVITY_CLEAR_TOP); i.setFlags(FLAG_ACTIVITY_CLEAR_TOP);
activity.startActivity(i); activity.startActivity(i);
}); });

View File

@@ -14,11 +14,11 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; 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.AddContactState.ContactExchangeStarted;
import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.Failed; import org.briarproject.briar.android.contact.add.nearby.AddContactState.Failed;
import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementStarted; import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementStarted;
import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementWaiting; import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementWaiting;
import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.QrCodeScanned; import org.briarproject.briar.android.contact.add.nearby.AddContactState.QrCodeScanned;
import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.view.QrCodeView; import org.briarproject.briar.android.view.QrCodeView;
@@ -42,26 +42,26 @@ import static org.briarproject.bramble.util.LogUtils.logException;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class KeyAgreementFragment extends BaseFragment public class AddNearbyContactFragment extends BaseFragment
implements QrCodeView.FullscreenListener { 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); private static final Logger LOG = Logger.getLogger(TAG);
@Inject @Inject
ViewModelProvider.Factory viewModelFactory; ViewModelProvider.Factory viewModelFactory;
private ContactExchangeViewModel viewModel; private AddNearbyContactViewModel viewModel;
private CameraView cameraView; private CameraView cameraView;
private LinearLayout cameraOverlay; private LinearLayout cameraOverlay;
private View statusView; private View statusView;
private QrCodeView qrCodeView; private QrCodeView qrCodeView;
private TextView status; private TextView status;
public static KeyAgreementFragment newInstance() { public static AddNearbyContactFragment newInstance() {
Bundle args = new Bundle(); Bundle args = new Bundle();
KeyAgreementFragment fragment = new KeyAgreementFragment(); AddNearbyContactFragment fragment = new AddNearbyContactFragment();
fragment.setArguments(args); fragment.setArguments(args);
return fragment; return fragment;
} }
@@ -70,7 +70,7 @@ public class KeyAgreementFragment extends BaseFragment
public void injectFragment(ActivityComponent component) { public void injectFragment(ActivityComponent component) {
component.inject(this); component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(ContactExchangeViewModel.class); .get(AddNearbyContactViewModel.class);
} }
@Nullable @Nullable
@@ -93,7 +93,7 @@ public class KeyAgreementFragment extends BaseFragment
qrCodeView.setFullscreenListener(this); qrCodeView.setFullscreenListener(this);
viewModel.getState().observe(getViewLifecycleOwner(), viewModel.getState().observe(getViewLifecycleOwner(),
this::onContactAddingStateChanged); this::onAddContactStateChanged);
} }
@Override @Override
@@ -153,10 +153,10 @@ public class KeyAgreementFragment extends BaseFragment
} }
@UiThread @UiThread
private void onContactAddingStateChanged(ContactAddingState state) { private void onAddContactStateChanged(AddContactState state) {
if (state instanceof ContactAddingState.KeyAgreementListening) { if (state instanceof AddContactState.KeyAgreementListening) {
Bitmap qrCode = Bitmap qrCode =
((ContactAddingState.KeyAgreementListening) state).qrCode; ((AddContactState.KeyAgreementListening) state).qrCode;
qrCodeView.setQrCode(qrCode); qrCodeView.setQrCode(qrCode);
} else if (state instanceof QrCodeScanned) { } else if (state instanceof QrCodeScanned) {
try { try {

View File

@@ -21,20 +21,21 @@ import static android.view.View.FOCUS_DOWN;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @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 @Inject
ViewModelProvider.Factory viewModelFactory; ViewModelProvider.Factory viewModelFactory;
private ContactExchangeViewModel viewModel; private AddNearbyContactViewModel viewModel;
private ScrollView scrollView; private ScrollView scrollView;
public static IntroFragment newInstance() { public static AddNearbyContactIntroFragment newInstance() {
Bundle args = new Bundle(); Bundle args = new Bundle();
IntroFragment fragment = new IntroFragment(); AddNearbyContactIntroFragment
fragment = new AddNearbyContactIntroFragment();
fragment.setArguments(args); fragment.setArguments(args);
return fragment; return fragment;
} }
@@ -43,7 +44,7 @@ public class IntroFragment extends BaseFragment {
public void injectFragment(ActivityComponent component) { public void injectFragment(ActivityComponent component) {
component.inject(this); component.inject(this);
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory) viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
.get(ContactExchangeViewModel.class); .get(AddNearbyContactViewModel.class);
} }
@Nullable @Nullable

View File

@@ -8,12 +8,12 @@ import dagger.Module;
import dagger.multibindings.IntoMap; import dagger.multibindings.IntoMap;
@Module @Module
public abstract class ContactExchangeModule { public abstract class AddNearbyContactModule {
@Binds @Binds
@IntoMap @IntoMap
@ViewModelKey(ContactExchangeViewModel.class) @ViewModelKey(AddNearbyContactViewModel.class)
abstract ViewModel bindContactExchangeViewModel( abstract ViewModel bindContactExchangeViewModel(
ContactExchangeViewModel contactExchangeViewModel); AddNearbyContactViewModel addNearbyContactViewModel);
} }

View File

@@ -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.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.plugin.event.TransportStateEvent; import org.briarproject.bramble.api.plugin.event.TransportStateEvent;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.ContactExchangeFinished; import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeFinished;
import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.ContactExchangeStarted; import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Error;
import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementListening; import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeResult.Success;
import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementStarted; import org.briarproject.briar.android.contact.add.nearby.AddContactState.ContactExchangeStarted;
import org.briarproject.briar.android.contact.add.nearby.ContactAddingState.KeyAgreementWaiting; import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementListening;
import org.briarproject.briar.android.contact.add.nearby.ContactExchangeResult.Error; import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementStarted;
import org.briarproject.briar.android.contact.add.nearby.ContactExchangeResult.Success; import org.briarproject.briar.android.contact.add.nearby.AddContactState.KeyAgreementWaiting;
import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.MutableLiveEvent; 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.INACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING; import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
import static org.briarproject.bramble.util.LogUtils.logException; 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.AddNearbyContactViewModel.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.UNKNOWN;
@NotNullByDefault @NotNullByDefault
class ContactExchangeViewModel extends AndroidViewModel class AddNearbyContactViewModel extends AndroidViewModel
implements EventListener, QrCodeDecoder.ResultCallback { implements EventListener, QrCodeDecoder.ResultCallback {
private static final Logger LOG = private static final Logger LOG =
getLogger(ContactExchangeViewModel.class.getName()); getLogger(AddNearbyContactViewModel.class.getName());
enum BluetoothDecision { enum BluetoothDecision {
/** /**
@@ -135,7 +135,7 @@ class ContactExchangeViewModel extends AndroidViewModel
new MutableLiveEvent<>(); new MutableLiveEvent<>();
private final MutableLiveEvent<TransportId> transportStateChanged = private final MutableLiveEvent<TransportId> transportStateChanged =
new MutableLiveEvent<>(); new MutableLiveEvent<>();
private final MutableLiveData<ContactAddingState> state = private final MutableLiveData<AddContactState> state =
new MutableLiveData<>(); new MutableLiveData<>();
final QrCodeDecoder qrCodeDecoder; final QrCodeDecoder qrCodeDecoder;
@@ -164,7 +164,7 @@ class ContactExchangeViewModel extends AndroidViewModel
private volatile boolean gotLocalPayload = false, gotRemotePayload = false; private volatile boolean gotLocalPayload = false, gotRemotePayload = false;
@Inject @Inject
ContactExchangeViewModel(Application app, AddNearbyContactViewModel(Application app,
EventBus eventBus, EventBus eventBus,
@IoExecutor Executor ioExecutor, @IoExecutor Executor ioExecutor,
PluginManager pluginManager, PluginManager pluginManager,
@@ -336,11 +336,11 @@ class ContactExchangeViewModel extends AndroidViewModel
} else if (e instanceof KeyAgreementAbortedEvent) { } else if (e instanceof KeyAgreementAbortedEvent) {
LOG.info("KeyAgreementAbortedEvent received"); LOG.info("KeyAgreementAbortedEvent received");
resetPayloadFlags(); resetPayloadFlags();
state.setValue(new ContactAddingState.Failed()); state.setValue(new AddContactState.Failed());
} else if (e instanceof KeyAgreementFailedEvent) { } else if (e instanceof KeyAgreementFailedEvent) {
LOG.info("KeyAgreementFailedEvent received"); LOG.info("KeyAgreementFailedEvent received");
resetPayloadFlags(); resetPayloadFlags();
state.setValue(new ContactAddingState.Failed()); state.setValue(new AddContactState.Failed());
} }
} }
@@ -377,16 +377,16 @@ class ContactExchangeViewModel extends AndroidViewModel
Payload remotePayload = payloadParser.parse(payloadBytes); Payload remotePayload = payloadParser.parse(payloadBytes);
gotRemotePayload = true; gotRemotePayload = true;
requireNonNull(task).connectAndRunProtocol(remotePayload); requireNonNull(task).connectAndRunProtocol(remotePayload);
state.postValue(new ContactAddingState.QrCodeScanned()); state.postValue(new AddContactState.QrCodeScanned());
} catch (UnsupportedVersionException e) { } catch (UnsupportedVersionException e) {
resetPayloadFlags(); resetPayloadFlags();
state.postValue(new ContactAddingState.Failed(e.isTooOld())); state.postValue(new AddContactState.Failed(e.isTooOld()));
} catch (IOException | IllegalArgumentException e) { } catch (IOException | IllegalArgumentException e) {
LOG.log(WARNING, "QR Code Invalid", e); LOG.log(WARNING, "QR Code Invalid", e);
Toast.makeText(getApplication(), R.string.qr_code_invalid, Toast.makeText(getApplication(), R.string.qr_code_invalid,
LENGTH_LONG).show(); LENGTH_LONG).show();
resetPayloadFlags(); resetPayloadFlags();
state.postValue(new ContactAddingState.Failed()); state.postValue(new AddContactState.Failed());
} }
} }
@@ -448,7 +448,7 @@ class ContactExchangeViewModel extends AndroidViewModel
return showQrCodeFragment; return showQrCodeFragment;
} }
LiveData<ContactAddingState> getState() { LiveData<AddContactState> getState() {
return state; return state;
} }

View File

@@ -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);
}
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}
}