mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Get rid of KeyAgreementEventListener
and communicate via ViewModel
This commit is contained in:
@@ -4,17 +4,17 @@ import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.briarproject.bramble.api.identity.Author;
|
||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementResult;
|
||||
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.ContactExchangeViewModel.KeyAgreementState;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import static android.widget.Toast.LENGTH_LONG;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.ABORTED;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.FAILED;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -25,77 +25,39 @@ public class ContactExchangeActivity extends KeyAgreementActivity {
|
||||
super.onCreate(state);
|
||||
requireNonNull(getSupportActionBar())
|
||||
.setTitle(R.string.add_contact_title);
|
||||
viewModel.getKeyAgreementState()
|
||||
.observe(this, this::onKeyAgreementStateChanged);
|
||||
viewModel.getContactExchangeResult()
|
||||
.observe(this, this::onContactExchangeResult);
|
||||
}
|
||||
|
||||
private void startContactExchange(KeyAgreementResult agreementResult) {
|
||||
viewModel.getContactExchangeResult().observe(this, result -> {
|
||||
if (result instanceof ContactExchangeResult.Success) {
|
||||
Author remoteAuthor =
|
||||
((ContactExchangeResult.Success) result).remoteAuthor;
|
||||
contactExchangeSucceeded(remoteAuthor);
|
||||
} else if (result instanceof ContactExchangeResult.Error) {
|
||||
Author duplicateAuthor =
|
||||
((ContactExchangeResult.Error) result).duplicateAuthor;
|
||||
if (duplicateAuthor == null) contactExchangeFailed();
|
||||
else duplicateContact(duplicateAuthor);
|
||||
} else throw new AssertionError();
|
||||
});
|
||||
viewModel.startContactExchange(agreementResult.getTransportId(),
|
||||
agreementResult.getConnection(), agreementResult.getMasterKey(),
|
||||
agreementResult.wasAlice());
|
||||
private void onKeyAgreementStateChanged(KeyAgreementState state) {
|
||||
if (state == ABORTED || state == FAILED) {
|
||||
showErrorFragment();
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void contactExchangeSucceeded(Author remoteAuthor) {
|
||||
String contactName = remoteAuthor.getName();
|
||||
String text = getString(R.string.contact_added_toast, contactName);
|
||||
Toast.makeText(this, text, LENGTH_LONG).show();
|
||||
supportFinishAfterTransition();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void duplicateContact(Author remoteAuthor) {
|
||||
String contactName = remoteAuthor.getName();
|
||||
String format = getString(R.string.contact_already_exists);
|
||||
String text = String.format(format, contactName);
|
||||
Toast.makeText(this, text, LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void contactExchangeFailed() {
|
||||
showErrorFragment();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public void keyAgreementFailed() {
|
||||
showErrorFragment();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public String keyAgreementWaiting() {
|
||||
return getString(R.string.waiting_for_contact_to_scan);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public String keyAgreementStarted() {
|
||||
return getString(R.string.authenticating_with_device);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public void keyAgreementAborted(boolean remoteAborted) {
|
||||
showErrorFragment();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public String keyAgreementFinished(KeyAgreementResult result) {
|
||||
startContactExchange(result);
|
||||
return getString(R.string.exchanging_contact_details);
|
||||
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 showErrorFragment() {
|
||||
|
||||
@@ -8,6 +8,15 @@ import org.briarproject.bramble.api.contact.ContactExchangeManager;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.event.EventListener;
|
||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementResult;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementAbortedEvent;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFailedEvent;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFinishedEvent;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementStartedEvent;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.plugin.TransportId;
|
||||
@@ -29,32 +38,75 @@ import androidx.lifecycle.MutableLiveData;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.ABORTED;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.FAILED;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.FINISHED;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.STARTED;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.WAITING;
|
||||
|
||||
@NotNullByDefault
|
||||
class ContactExchangeViewModel extends AndroidViewModel {
|
||||
class ContactExchangeViewModel extends AndroidViewModel
|
||||
implements EventListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
getLogger(ContactExchangeViewModel.class.getName());
|
||||
|
||||
enum KeyAgreementState {
|
||||
WAITING, STARTED, FINISHED, ABORTED, FAILED
|
||||
}
|
||||
|
||||
private final EventBus eventBus;
|
||||
private final Executor ioExecutor;
|
||||
private final ContactExchangeManager contactExchangeManager;
|
||||
private final ConnectionManager connectionManager;
|
||||
private final MutableLiveData<KeyAgreementState> keyAgreementState =
|
||||
new MutableLiveData<>();
|
||||
private final MutableLiveData<ContactExchangeResult> exchangeResult =
|
||||
new MutableLiveData<>();
|
||||
|
||||
@Inject
|
||||
ContactExchangeViewModel(Application app, @IoExecutor Executor ioExecutor,
|
||||
ContactExchangeViewModel(Application app,
|
||||
EventBus eventBus,
|
||||
@IoExecutor Executor ioExecutor,
|
||||
ContactExchangeManager contactExchangeManager,
|
||||
ConnectionManager connectionManager) {
|
||||
super(app);
|
||||
this.eventBus = eventBus;
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.contactExchangeManager = contactExchangeManager;
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
super.onCleared();
|
||||
eventBus.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof KeyAgreementWaitingEvent) {
|
||||
keyAgreementState.setValue(WAITING);
|
||||
} else if (e instanceof KeyAgreementStartedEvent) {
|
||||
keyAgreementState.setValue(STARTED);
|
||||
} else if (e instanceof KeyAgreementAbortedEvent) {
|
||||
keyAgreementState.setValue(ABORTED);
|
||||
} else if (e instanceof KeyAgreementFinishedEvent) {
|
||||
keyAgreementState.setValue(FINISHED);
|
||||
KeyAgreementResult result =
|
||||
((KeyAgreementFinishedEvent) e).getResult();
|
||||
startContactExchange(result);
|
||||
} else if (e instanceof KeyAgreementFailedEvent) {
|
||||
keyAgreementState.setValue(FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
void startContactExchange(TransportId t, DuplexTransportConnection conn,
|
||||
SecretKey masterKey, boolean alice) {
|
||||
private void startContactExchange(KeyAgreementResult result) {
|
||||
TransportId t = result.getTransportId();
|
||||
DuplexTransportConnection conn = result.getConnection();
|
||||
SecretKey masterKey = result.getMasterKey();
|
||||
boolean alice = result.wasAlice();
|
||||
ioExecutor.execute(() -> {
|
||||
try {
|
||||
Contact contact = contactExchangeManager.exchangeContacts(conn,
|
||||
@@ -83,6 +135,10 @@ class ContactExchangeViewModel extends AndroidViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
LiveData<KeyAgreementState> getKeyAgreementState() {
|
||||
return keyAgreementState;
|
||||
}
|
||||
|
||||
LiveData<ContactExchangeResult> getContactExchangeResult() {
|
||||
return exchangeResult;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ 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.IntroFragment.IntroScreenSeenListener;
|
||||
import org.briarproject.briar.android.contact.add.nearby.KeyAgreementFragment.KeyAgreementEventListener;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
|
||||
|
||||
@@ -61,8 +60,7 @@ import static org.briarproject.briar.android.util.UiUtils.getGoToSettingsListene
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public abstract class KeyAgreementActivity extends BriarActivity implements
|
||||
BaseFragmentListener, IntroScreenSeenListener,
|
||||
KeyAgreementEventListener, EventListener {
|
||||
BaseFragmentListener, IntroScreenSeenListener, EventListener {
|
||||
|
||||
private enum BluetoothDecision {
|
||||
/**
|
||||
|
||||
@@ -17,23 +17,17 @@ import com.google.zxing.Result;
|
||||
import org.briarproject.bramble.api.UnsupportedVersionException;
|
||||
import org.briarproject.bramble.api.event.Event;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementResult;
|
||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
|
||||
import org.briarproject.bramble.api.keyagreement.Payload;
|
||||
import org.briarproject.bramble.api.keyagreement.PayloadEncoder;
|
||||
import org.briarproject.bramble.api.keyagreement.PayloadParser;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementAbortedEvent;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFailedEvent;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementFinishedEvent;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementStartedEvent;
|
||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementWaitingEvent;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
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.ContactExchangeViewModel.KeyAgreementState;
|
||||
import org.briarproject.briar.android.fragment.BaseEventFragment;
|
||||
import org.briarproject.briar.android.view.QrCodeView;
|
||||
|
||||
@@ -47,6 +41,8 @@ import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
|
||||
import static android.view.View.INVISIBLE;
|
||||
@@ -57,6 +53,11 @@ import static android.widget.Toast.LENGTH_LONG;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.ABORTED;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.FAILED;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.FINISHED;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.STARTED;
|
||||
import static org.briarproject.briar.android.contact.add.nearby.ContactExchangeViewModel.KeyAgreementState.WAITING;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
@@ -69,6 +70,8 @@ public class KeyAgreementFragment extends BaseEventFragment
|
||||
@SuppressWarnings("CharsetObjectCanBeUsed") // Requires minSdkVersion >= 19
|
||||
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
||||
|
||||
@Inject
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
@Inject
|
||||
Provider<KeyAgreementTask> keyAgreementTaskProvider;
|
||||
@Inject
|
||||
@@ -81,6 +84,7 @@ public class KeyAgreementFragment extends BaseEventFragment
|
||||
@Inject
|
||||
EventBus eventBus;
|
||||
|
||||
private ContactExchangeViewModel viewModel;
|
||||
private CameraView cameraView;
|
||||
private LinearLayout cameraOverlay;
|
||||
private View statusView;
|
||||
@@ -90,7 +94,6 @@ public class KeyAgreementFragment extends BaseEventFragment
|
||||
private boolean gotRemotePayload;
|
||||
private volatile boolean gotLocalPayload;
|
||||
private KeyAgreementTask task;
|
||||
private KeyAgreementEventListener listener;
|
||||
|
||||
public static KeyAgreementFragment newInstance() {
|
||||
Bundle args = new Bundle();
|
||||
@@ -99,15 +102,11 @@ public class KeyAgreementFragment extends BaseEventFragment
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
listener = (KeyAgreementEventListener) context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectFragment(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
viewModel = new ViewModelProvider(requireActivity(), viewModelFactory)
|
||||
.get(ContactExchangeViewModel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,6 +132,10 @@ public class KeyAgreementFragment extends BaseEventFragment
|
||||
status = view.findViewById(R.id.connect_status);
|
||||
qrCodeView = view.findViewById(R.id.qr_code_view);
|
||||
qrCodeView.setFullscreenListener(this);
|
||||
|
||||
LifecycleOwner lifecycleOwner = getViewLifecycleOwner();
|
||||
viewModel.getKeyAgreementState()
|
||||
.observe(lifecycleOwner, this::onKeyAgreementStateChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -271,48 +274,23 @@ public class KeyAgreementFragment extends BaseEventFragment
|
||||
KeyAgreementListeningEvent event = (KeyAgreementListeningEvent) e;
|
||||
gotLocalPayload = true;
|
||||
setQrCode(event.getLocalPayload());
|
||||
} else if (e instanceof KeyAgreementFailedEvent) {
|
||||
keyAgreementFailed();
|
||||
} else if (e instanceof KeyAgreementWaitingEvent) {
|
||||
keyAgreementWaiting();
|
||||
} else if (e instanceof KeyAgreementStartedEvent) {
|
||||
keyAgreementStarted();
|
||||
} else if (e instanceof KeyAgreementAbortedEvent) {
|
||||
KeyAgreementAbortedEvent event = (KeyAgreementAbortedEvent) e;
|
||||
keyAgreementAborted(event.didRemoteAbort());
|
||||
} else if (e instanceof KeyAgreementFinishedEvent) {
|
||||
keyAgreementFinished(((KeyAgreementFinishedEvent) e).getResult());
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void keyAgreementFailed() {
|
||||
reset();
|
||||
listener.keyAgreementFailed();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void keyAgreementWaiting() {
|
||||
status.setText(listener.keyAgreementWaiting());
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void keyAgreementStarted() {
|
||||
qrCodeView.setVisibility(INVISIBLE);
|
||||
statusView.setVisibility(VISIBLE);
|
||||
status.setText(listener.keyAgreementStarted());
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void keyAgreementAborted(boolean remoteAborted) {
|
||||
reset();
|
||||
listener.keyAgreementAborted(remoteAborted);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void keyAgreementFinished(KeyAgreementResult result) {
|
||||
statusView.setVisibility(VISIBLE);
|
||||
status.setText(listener.keyAgreementFinished(result));
|
||||
private void onKeyAgreementStateChanged(KeyAgreementState state) {
|
||||
if (state == WAITING) {
|
||||
status.setText(R.string.waiting_for_contact_to_scan);
|
||||
} else if (state == STARTED) {
|
||||
qrCodeView.setVisibility(INVISIBLE);
|
||||
statusView.setVisibility(VISIBLE);
|
||||
status.setText(R.string.authenticating_with_device);
|
||||
} else if (state == FINISHED) {
|
||||
statusView.setVisibility(VISIBLE);
|
||||
status.setText(R.string.exchanging_contact_details);
|
||||
} else if (state == ABORTED || state == FAILED) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
private void setQrCode(Payload localPayload) {
|
||||
@@ -328,7 +306,8 @@ public class KeyAgreementFragment extends BaseEventFragment
|
||||
// Use ISO 8859-1 to encode bytes directly as a string
|
||||
String content = new String(payloadBytes, ISO_8859_1);
|
||||
Bitmap qrCode = QrCodeUtils.createQrCode(dm, content);
|
||||
runOnUiThreadUnlessDestroyed(() -> qrCodeView.setQrCode(qrCode));
|
||||
runOnUiThreadUnlessDestroyed(
|
||||
() -> qrCodeView.setQrCode(qrCode));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -347,29 +326,4 @@ public class KeyAgreementFragment extends BaseEventFragment
|
||||
requireActivity().getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
|
||||
@NotNullByDefault
|
||||
interface KeyAgreementEventListener {
|
||||
|
||||
@UiThread
|
||||
void keyAgreementFailed();
|
||||
|
||||
// Should return a string to be displayed as status.
|
||||
@UiThread
|
||||
@Nullable
|
||||
String keyAgreementWaiting();
|
||||
|
||||
// Should return a string to be displayed as status.
|
||||
@UiThread
|
||||
@Nullable
|
||||
String keyAgreementStarted();
|
||||
|
||||
// Will show an error fragment.
|
||||
@UiThread
|
||||
void keyAgreementAborted(boolean remoteAborted);
|
||||
|
||||
// Should return a string to be displayed as status.
|
||||
@UiThread
|
||||
@Nullable
|
||||
String keyAgreementFinished(KeyAgreementResult result);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user