Move background work into view model.

This commit is contained in:
akwizgran
2019-05-09 17:41:41 +01:00
parent da54712ae1
commit 9ea91cbb3e
5 changed files with 137 additions and 51 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -14,6 +14,6 @@ import dagger.MapKey;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
public @interface ViewModelKey {
Class<? extends ViewModel> value();
}