From 9ea91cbb3e95e7134dedac8cf4b166801b78427e Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 9 May 2019 17:41:41 +0100 Subject: [PATCH] Move background work into view model. --- .../briarproject/briar/android/AppModule.java | 3 +- .../keyagreement/ContactExchangeActivity.java | 70 +++++--------- .../keyagreement/ContactExchangeModule.java | 20 ++++ .../ContactExchangeViewModel.java | 93 +++++++++++++++++++ .../briar/android/viewmodel/ViewModelKey.java | 2 +- 5 files changed, 137 insertions(+), 51 deletions(-) create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeModule.java create mode 100644 briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeViewModel.java 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 c3ccaa9cc..55e966549 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 @@ -33,6 +33,7 @@ import org.briarproject.bramble.plugin.tor.CircumventionProvider; import org.briarproject.bramble.util.AndroidUtils; import org.briarproject.bramble.util.StringUtils; import org.briarproject.briar.android.account.LockManagerImpl; +import org.briarproject.briar.android.keyagreement.ContactExchangeModule; import org.briarproject.briar.android.viewmodel.ViewModelModule; import org.briarproject.briar.api.android.AndroidNotificationManager; import org.briarproject.briar.api.android.DozeWatchdog; @@ -59,7 +60,7 @@ import static java.util.Collections.emptyList; import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_ONION_ADDRESS; import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBLIC_KEY_HEX; -@Module(includes = ViewModelModule.class) +@Module(includes = {ContactExchangeModule.class, ViewModelModule.class}) public class AppModule { static class EagerSingletons { diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java index 9d8f661e2..7372ae2ae 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java @@ -1,24 +1,18 @@ package org.briarproject.briar.android.keyagreement; +import android.arch.lifecycle.ViewModelProvider; +import android.arch.lifecycle.ViewModelProviders; import android.os.Bundle; import android.support.annotation.UiThread; import android.widget.Toast; -import org.briarproject.bramble.api.contact.ContactExchangeManager; -import org.briarproject.bramble.api.contact.event.ContactExchangeFailedEvent; -import org.briarproject.bramble.api.contact.event.ContactExchangeSucceededEvent; -import org.briarproject.bramble.api.event.Event; -import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.keyagreement.KeyAgreementResult; -import org.briarproject.bramble.api.lifecycle.IoExecutor; 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 java.util.concurrent.Executor; - import javax.annotation.Nullable; import javax.inject.Inject; @@ -27,16 +21,12 @@ import static java.util.Objects.requireNonNull; @MethodsNotNullByDefault @ParametersNotNullByDefault -public class ContactExchangeActivity extends KeyAgreementActivity implements - EventListener { +public class ContactExchangeActivity extends KeyAgreementActivity { @Inject - @IoExecutor - Executor ioExecutor; + ViewModelProvider.Factory viewModelFactory; - // Fields that are accessed from background threads must be volatile - @Inject - volatile ContactExchangeManager contactExchangeManager; + private ContactExchangeViewModel viewModel; @Override public void injectActivity(ActivityComponent component) { @@ -46,45 +36,27 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements @Override public void onCreate(@Nullable Bundle state) { super.onCreate(state); - getSupportActionBar().setTitle(R.string.add_contact_title); - } - - @Override - public void onStart() { - super.onStart(); - // Listen to updates from ContactExchangeManager - eventBus.addListener(this); - } - - @Override - protected void onStop() { - super.onStop(); - // Stop listening to updates from ContactExchangeManager - eventBus.addListener(this); + requireNonNull(getSupportActionBar()) + .setTitle(R.string.add_contact_title); + viewModel = ViewModelProviders.of(this, viewModelFactory) + .get(ContactExchangeViewModel.class); } private void startContactExchange(KeyAgreementResult result) { - ioExecutor.execute(() -> { - // Exchange contact details - contactExchangeManager.exchangeContacts(result.getTransportId(), - result.getConnection(), result.getMasterKey(), - result.wasAlice()); - }); - } - - @Override - public void eventOccurred(Event e) { - if (e instanceof ContactExchangeSucceededEvent) { - ContactExchangeSucceededEvent c = (ContactExchangeSucceededEvent) e; - contactExchangeSucceeded(c.getRemoteAuthor()); - } else if (e instanceof ContactExchangeFailedEvent) { - ContactExchangeFailedEvent c = (ContactExchangeFailedEvent) e; - if (c.wasDuplicateContact()) { - duplicateContact(requireNonNull(c.getDuplicateRemoteAuthor())); + viewModel.getSucceeded().observe(this, succeeded -> { + if (succeeded == null) return; + if (succeeded) { + Author remote = requireNonNull(viewModel.getRemoteAuthor()); + contactExchangeSucceeded(remote); } else { - contactExchangeFailed(); + Author duplicate = viewModel.getDuplicateAuthor(); + if (duplicate == null) contactExchangeFailed(); + else duplicateContact(duplicate); } - } + }); + viewModel.startContactExchange(result.getTransportId(), + result.getConnection(), result.getMasterKey(), + result.wasAlice()); } @UiThread diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeModule.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeModule.java new file mode 100644 index 000000000..65baf1e70 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeModule.java @@ -0,0 +1,20 @@ +package org.briarproject.briar.android.keyagreement; + +import android.arch.lifecycle.ViewModel; + +import org.briarproject.briar.android.viewmodel.ViewModelKey; + +import dagger.Binds; +import dagger.Module; +import dagger.multibindings.IntoMap; + +@Module +public abstract class ContactExchangeModule { + + @Binds + @IntoMap + @ViewModelKey(ContactExchangeViewModel.class) + abstract ViewModel bindContactExchangeViewModel( + ContactExchangeViewModel contactExchangeViewModel); + +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeViewModel.java new file mode 100644 index 000000000..5b990f2d8 --- /dev/null +++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeViewModel.java @@ -0,0 +1,93 @@ +package org.briarproject.briar.android.keyagreement; + +import android.app.Application; +import android.arch.lifecycle.AndroidViewModel; +import android.arch.lifecycle.LiveData; +import android.arch.lifecycle.MutableLiveData; +import android.support.annotation.UiThread; + +import org.briarproject.bramble.api.contact.ContactExchangeManager; +import org.briarproject.bramble.api.contact.event.ContactExchangeFailedEvent; +import org.briarproject.bramble.api.contact.event.ContactExchangeSucceededEvent; +import org.briarproject.bramble.api.crypto.SecretKey; +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.identity.Author; +import org.briarproject.bramble.api.lifecycle.IoExecutor; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; + +import java.util.concurrent.Executor; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +import static java.util.Objects.requireNonNull; + +@NotNullByDefault +class ContactExchangeViewModel extends AndroidViewModel + implements EventListener { + + private final Executor ioExecutor; + private final ContactExchangeManager contactExchangeManager; + private final EventBus eventBus; + private final MutableLiveData succeeded = new MutableLiveData<>(); + + @Nullable + private Author remoteAuthor, duplicateAuthor; + + @Inject + ContactExchangeViewModel(Application app, @IoExecutor Executor ioExecutor, + ContactExchangeManager contactExchangeManager, EventBus eventBus) { + super(app); + this.ioExecutor = ioExecutor; + this.contactExchangeManager = contactExchangeManager; + this.eventBus = eventBus; + eventBus.addListener(this); + } + + @Override + protected void onCleared() { + super.onCleared(); + eventBus.removeListener(this); + } + + @UiThread + void startContactExchange(TransportId t, DuplexTransportConnection conn, + SecretKey masterKey, boolean alice) { + ioExecutor.execute(() -> contactExchangeManager.exchangeContacts(t, + conn, masterKey, alice)); + } + + @UiThread + @Nullable + Author getRemoteAuthor() { + return remoteAuthor; + } + + @UiThread + @Nullable + Author getDuplicateAuthor() { + return duplicateAuthor; + } + + LiveData getSucceeded() { + return succeeded; + } + + @Override + public void eventOccurred(Event e) { + if (e instanceof ContactExchangeSucceededEvent) { + ContactExchangeSucceededEvent c = (ContactExchangeSucceededEvent) e; + remoteAuthor = c.getRemoteAuthor(); + succeeded.setValue(true); + } else if (e instanceof ContactExchangeFailedEvent) { + ContactExchangeFailedEvent c = (ContactExchangeFailedEvent) e; + if (c.wasDuplicateContact()) + duplicateAuthor = requireNonNull(c.getDuplicateRemoteAuthor()); + succeeded.setValue(false); + } + } +} diff --git a/briar-android/src/main/java/org/briarproject/briar/android/viewmodel/ViewModelKey.java b/briar-android/src/main/java/org/briarproject/briar/android/viewmodel/ViewModelKey.java index bd4f3d650..66288e9bb 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/viewmodel/ViewModelKey.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/viewmodel/ViewModelKey.java @@ -14,6 +14,6 @@ import dagger.MapKey; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @MapKey -@interface ViewModelKey { +public @interface ViewModelKey { Class value(); }