From a14e981236b7582ae246244625d7458f14098d27 Mon Sep 17 00:00:00 2001
From: Ernir Erlingsson <ernir@ymirmobile.com>
Date: Thu, 7 Apr 2016 12:54:23 +0200
Subject: [PATCH] Switched AppBus for ResultHandler, Controller for Helper.
 Added the basics for LifecycleControllers and implemented it for
 BriarActivity and NavDrawerActivity

---
 .../briarproject/android/ActivityModule.java  |  66 ++++++--
 .../android/AndroidComponent.java             |   5 -
 .../briarproject/android/BaseActivity.java    |  48 ++++--
 .../briarproject/android/BriarActivity.java   |  98 ++++-------
 .../briarproject/android/BriarService.java    |   2 +-
 .../android/NavDrawerActivity.java            | 110 ++++--------
 .../android/PasswordActivity.java             |  39 ++---
 .../briarproject/android/SetupActivity.java   |  49 +++---
 .../android/SplashScreenActivity.java         |   8 +-
 .../ActivityLifecycleController.java          |  11 ++
 .../android/controller/BriarController.java   |  14 ++
 .../controller/BriarControllerImp.java        | 123 ++++++++++++++
 .../ConfigController.java}                    |   4 +-
 .../ConfigControllerImp.java}                 |   6 +-
 .../controller/EncryptedKeyNullException.java |   9 +
 .../controller/NavDrawerController.java       |  16 ++
 .../controller/NavDrawerControllerImp.java    | 159 ++++++++++++++++++
 .../controller/PasswordController.java        |   6 +
 .../PasswordControllerImp.java}               |  29 ++--
 .../android/controller/ResultHandler.java     |   6 +
 .../android/controller/SetupController.java   |   8 +
 .../SetupControllerImp.java}                  |  27 ++-
 .../controller/TransportStateListener.java    |   7 +
 .../briarproject/android/event/AppBus.java    |   6 -
 .../briarproject/android/event/AppBusImp.java |  25 ---
 .../android/event/ErrorEvent.java             |  10 --
 .../event/LocalAuthorCreatedEvent.java        |  16 --
 .../android/event/PasswordValidateEvent.java  |  16 --
 .../android/helper/PasswordHelper.java        |   5 -
 .../android/helper/SetupHelper.java           |   6 -
 .../invitation/AddContactActivity.java        |   2 +-
 .../android/panic/PanicResponderActivity.java |   8 +-
 32 files changed, 586 insertions(+), 358 deletions(-)
 create mode 100644 briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java
 create mode 100644 briar-android/src/org/briarproject/android/controller/BriarController.java
 create mode 100644 briar-android/src/org/briarproject/android/controller/BriarControllerImp.java
 rename briar-android/src/org/briarproject/android/{helper/ConfigHelper.java => controller/ConfigController.java} (50%)
 rename briar-android/src/org/briarproject/android/{helper/ConfigHelperImp.java => controller/ConfigControllerImp.java} (83%)
 create mode 100644 briar-android/src/org/briarproject/android/controller/EncryptedKeyNullException.java
 create mode 100644 briar-android/src/org/briarproject/android/controller/NavDrawerController.java
 create mode 100644 briar-android/src/org/briarproject/android/controller/NavDrawerControllerImp.java
 create mode 100644 briar-android/src/org/briarproject/android/controller/PasswordController.java
 rename briar-android/src/org/briarproject/android/{helper/PasswordHelperImp.java => controller/PasswordControllerImp.java} (57%)
 create mode 100644 briar-android/src/org/briarproject/android/controller/ResultHandler.java
 create mode 100644 briar-android/src/org/briarproject/android/controller/SetupController.java
 rename briar-android/src/org/briarproject/android/{helper/SetupHelperImp.java => controller/SetupControllerImp.java} (83%)
 create mode 100644 briar-android/src/org/briarproject/android/controller/TransportStateListener.java
 delete mode 100644 briar-android/src/org/briarproject/android/event/AppBus.java
 delete mode 100644 briar-android/src/org/briarproject/android/event/AppBusImp.java
 delete mode 100644 briar-android/src/org/briarproject/android/event/ErrorEvent.java
 delete mode 100644 briar-android/src/org/briarproject/android/event/LocalAuthorCreatedEvent.java
 delete mode 100644 briar-android/src/org/briarproject/android/event/PasswordValidateEvent.java
 delete mode 100644 briar-android/src/org/briarproject/android/helper/PasswordHelper.java
 delete mode 100644 briar-android/src/org/briarproject/android/helper/SetupHelper.java

diff --git a/briar-android/src/org/briarproject/android/ActivityModule.java b/briar-android/src/org/briarproject/android/ActivityModule.java
index 1f398b8e57..33e291abc3 100644
--- a/briar-android/src/org/briarproject/android/ActivityModule.java
+++ b/briar-android/src/org/briarproject/android/ActivityModule.java
@@ -6,14 +6,19 @@ import android.content.SharedPreferences;
 import android.os.Bundle;
 
 import org.briarproject.android.contact.ContactListFragment;
+import org.briarproject.android.controller.BriarController;
+import org.briarproject.android.controller.BriarControllerImp;
+import org.briarproject.android.controller.NavDrawerController;
+import org.briarproject.android.controller.NavDrawerControllerImp;
+import org.briarproject.android.controller.TransportStateListener;
 import org.briarproject.android.forum.ForumListFragment;
 import org.briarproject.android.fragment.BaseFragment;
-import org.briarproject.android.helper.PasswordHelper;
-import org.briarproject.android.helper.PasswordHelperImp;
-import org.briarproject.android.helper.SetupHelper;
-import org.briarproject.android.helper.SetupHelperImp;
-import org.briarproject.android.helper.ConfigHelper;
-import org.briarproject.android.helper.ConfigHelperImp;
+import org.briarproject.android.controller.PasswordController;
+import org.briarproject.android.controller.PasswordControllerImp;
+import org.briarproject.android.controller.SetupController;
+import org.briarproject.android.controller.SetupControllerImp;
+import org.briarproject.android.controller.ConfigController;
+import org.briarproject.android.controller.ConfigControllerImp;
 import org.briarproject.android.keyagreement.ChooseIdentityFragment;
 import org.briarproject.android.keyagreement.ShowQrCodeFragment;
 
@@ -22,6 +27,8 @@ import javax.inject.Named;
 import dagger.Module;
 import dagger.Provides;
 
+import static org.briarproject.android.BriarService.*;
+
 @Module
 public class ActivityModule {
 
@@ -31,6 +38,12 @@ public class ActivityModule {
 		this.activity = activity;
 	}
 
+	@ActivityScope
+	@Provides
+	BaseActivity providesBaseActivity() {
+		return activity;
+	}
+
 	@ActivityScope
 	@Provides
 	Activity providesActivity() {
@@ -39,14 +52,16 @@ public class ActivityModule {
 
 	@ActivityScope
 	@Provides
-	SetupHelper provideSetupHelper(SetupHelperImp setupHelperImp) {
-		return setupHelperImp;
+	SetupController provideSetupController(
+			SetupControllerImp setupControllerImp) {
+		return setupControllerImp;
 	}
 
 	@ActivityScope
 	@Provides
-	ConfigHelper provideConfigHelper(ConfigHelperImp configHelperImp) {
-		return configHelperImp;
+	ConfigController provideConfigController(
+			ConfigControllerImp configControllerImp) {
+		return configControllerImp;
 	}
 
 	@ActivityScope
@@ -57,8 +72,35 @@ public class ActivityModule {
 
 	@ActivityScope
 	@Provides
-	PasswordHelper providePasswordHelper(PasswordHelperImp passwordHelperImp) {
-		return passwordHelperImp;
+	PasswordController providePasswordController(
+			PasswordControllerImp passwordControllerImp) {
+		return passwordControllerImp;
+	}
+
+	@ActivityScope
+	@Provides
+	BriarController provideBriarController(
+			BriarControllerImp briarControllerImp) {
+		activity.addLifecycleController(briarControllerImp);
+		return briarControllerImp;
+	}
+
+	@ActivityScope
+	@Provides
+	NavDrawerController provideNavDrawerController(
+			NavDrawerControllerImp navDrawerControllerImp) {
+		activity.addLifecycleController(navDrawerControllerImp);
+		if (activity instanceof TransportStateListener) {
+			navDrawerControllerImp
+					.setTransportListener((TransportStateListener) activity);
+		}
+		return navDrawerControllerImp;
+	}
+
+	@ActivityScope
+	@Provides
+	BriarServiceConnection provideBriarServiceConnection() {
+		return new BriarServiceConnection();
 	}
 
 	@Provides
diff --git a/briar-android/src/org/briarproject/android/AndroidComponent.java b/briar-android/src/org/briarproject/android/AndroidComponent.java
index f482e52981..c5396da798 100644
--- a/briar-android/src/org/briarproject/android/AndroidComponent.java
+++ b/briar-android/src/org/briarproject/android/AndroidComponent.java
@@ -4,9 +4,6 @@ import org.briarproject.CoreEagerSingletons;
 import org.briarproject.CoreModule;
 import org.briarproject.android.api.AndroidNotificationManager;
 import org.briarproject.android.api.ReferenceManager;
-import org.briarproject.android.contact.ContactListFragment;
-import org.briarproject.android.contact.ConversationActivity;
-import org.briarproject.android.event.AppBus;
 import org.briarproject.api.contact.ContactExchangeTask;
 import org.briarproject.api.contact.ContactManager;
 import org.briarproject.api.crypto.CryptoComponent;
@@ -68,8 +65,6 @@ public interface AndroidComponent extends CoreEagerSingletons {
 
 	EventBus eventBus();
 
-	AppBus appEventBus();
-
 	InvitationTaskFactory invitationTaskFactory();
 
 	AndroidNotificationManager androidNotificationManager();
diff --git a/briar-android/src/org/briarproject/android/BaseActivity.java b/briar-android/src/org/briarproject/android/BaseActivity.java
index 213088daa8..1bbbc6fdec 100644
--- a/briar-android/src/org/briarproject/android/BaseActivity.java
+++ b/briar-android/src/org/briarproject/android/BaseActivity.java
@@ -2,29 +2,31 @@ package org.briarproject.android;
 
 import android.os.Bundle;
 import android.os.IBinder;
-import android.support.annotation.CallSuper;
+import android.os.PersistableBundle;
 import android.support.v7.app.AppCompatActivity;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 
-import org.briarproject.android.event.AppBus;
-import org.briarproject.android.event.ErrorEvent;
-import org.briarproject.api.event.Event;
-import org.briarproject.api.event.EventListener;
+import org.briarproject.android.controller.ActivityLifecycleController;
 
-import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
 
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
 import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS;
 
-public abstract class BaseActivity extends AppCompatActivity implements
-		EventListener {
+public abstract class BaseActivity extends AppCompatActivity {
 
 	protected ActivityComponent activityComponent;
 
-	@Inject
-	protected AppBus appBus;
+	private List<ActivityLifecycleController> lifecycleControllers =
+			new ArrayList<ActivityLifecycleController>();
+
+	public void addLifecycleController(
+			ActivityLifecycleController lifecycleController) {
+		this.lifecycleControllers.add(lifecycleController);
+	}
 
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
@@ -43,23 +45,37 @@ public abstract class BaseActivity extends AppCompatActivity implements
 		injectActivity(activityComponent);
 	}
 
+	@Override
+	public void onPostCreate(Bundle savedInstanceState,
+			PersistableBundle persistentState) {
+		super.onPostCreate(savedInstanceState, persistentState);
+		for (ActivityLifecycleController alc : lifecycleControllers) {
+			alc.onActivityCreate();
+		}
+
+	}
+
 	@Override
 	protected void onResume() {
 		super.onResume();
-		appBus.addListener(this);
+		for (ActivityLifecycleController alc : lifecycleControllers) {
+			alc.onActivityResume();
+		}
 	}
 
 	@Override
 	protected void onPause() {
-		appBus.removeListener(this);
 		super.onPause();
+		for (ActivityLifecycleController alc : lifecycleControllers) {
+			alc.onActivityPause();
+		}
 	}
 
 	@Override
-	@CallSuper
-	public void eventOccurred(Event e) {
-		if (e instanceof ErrorEvent) {
-			finish();
+	protected void onDestroy() {
+		super.onDestroy();
+		for (ActivityLifecycleController alc : lifecycleControllers) {
+			alc.onActivityDestroy();
 		}
 	}
 
diff --git a/briar-android/src/org/briarproject/android/BriarActivity.java b/briar-android/src/org/briarproject/android/BriarActivity.java
index 8043b1a140..a61e4059dc 100644
--- a/briar-android/src/org/briarproject/android/BriarActivity.java
+++ b/briar-android/src/org/briarproject/android/BriarActivity.java
@@ -8,6 +8,8 @@ import android.os.IBinder;
 
 import org.briarproject.android.BriarService.BriarBinder;
 import org.briarproject.android.BriarService.BriarServiceConnection;
+import org.briarproject.android.controller.BriarController;
+import org.briarproject.android.controller.ResultHandler;
 import org.briarproject.android.panic.ExitActivity;
 import org.briarproject.api.db.DatabaseConfig;
 import org.briarproject.api.db.DatabaseExecutor;
@@ -37,12 +39,12 @@ public abstract class BriarActivity extends BaseActivity {
 	private static final Logger LOG =
 			Logger.getLogger(BriarActivity.class.getName());
 
+	/*
 	private final BriarServiceConnection serviceConnection =
 			new BriarServiceConnection();
 
 	@Inject
-	protected DatabaseConfig databaseConfig;
-
+	DatabaseConfig databaseConfig;
 	private boolean bound = false;
 
 	// Fields that are accessed from background threads must be volatile
@@ -51,19 +53,23 @@ public abstract class BriarActivity extends BaseActivity {
 	protected volatile Executor dbExecutor;
 	@Inject
 	protected volatile LifecycleManager lifecycleManager;
+	*/
+	@Inject
+	protected BriarController briarController;
 
 	@Override
 	public void onCreate(Bundle state) {
 		super.onCreate(state);
 
-		if (databaseConfig.getEncryptionKey() != null) startAndBindService();
+		briarController.startAndBindService();
+//		if (databaseConfig.getEncryptionKey() != null) startAndBindService();
 	}
 
 	@Override
 	protected void onActivityResult(int request, int result, Intent data) {
 		super.onActivityResult(request, result, data);
 		if (request == REQUEST_PASSWORD) {
-			if (result == RESULT_OK) startAndBindService();
+			if (result == RESULT_OK) briarController.startAndBindService();
 			else finish();
 		}
 	}
@@ -71,7 +77,7 @@ public abstract class BriarActivity extends BaseActivity {
 	@Override
 	public void onResume() {
 		super.onResume();
-		if (databaseConfig.getEncryptionKey() == null && !isFinishing()) {
+		if (!briarController.encryptionKey() && !isFinishing()) {
 			Intent i = new Intent(this, PasswordActivity.class);
 			i.setFlags(FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_SINGLE_TOP);
 			startActivityForResult(i, REQUEST_PASSWORD);
@@ -81,41 +87,22 @@ public abstract class BriarActivity extends BaseActivity {
 	@Override
 	public void onDestroy() {
 		super.onDestroy();
-		unbindService();
-	}
-
-	private void startAndBindService() {
-		startService(new Intent(this, BriarService.class));
-		bound = bindService(new Intent(this, BriarService.class),
-				serviceConnection, 0);
-	}
-
-	private void unbindService() {
-		if (bound) unbindService(serviceConnection);
+		briarController.unbindService();
 	}
 
 	protected void signOut(final boolean removeFromRecentApps) {
-		// Use a new thread to avoid deadlock with executor tasks
-		new Thread() {
+		briarController.signOut(new ResultHandler<Void, RuntimeException>() {
 			@Override
-			public void run() {
-				try {
-					// Wait for the service to finish starting up
-					IBinder binder = serviceConnection.waitForBinder();
-					BriarService service = ((BriarBinder) binder).getService();
-					service.waitForStartup();
-					// Shut down the service and wait for it to shut down
-					LOG.info("Shutting down service");
-					service.shutdown();
-					service.waitForShutdown();
-				} catch (InterruptedException e) {
-					LOG.warning("Interrupted while waiting for service");
-					Thread.currentThread().interrupt();
-				}
+			public void onResult(Void result) {
 				if (removeFromRecentApps) startExitActivity();
 				else finishAndExit();
 			}
-		}.start();
+
+			@Override
+			public void onException(RuntimeException exception) {
+				// TODO ?
+			}
+		});
 	}
 
 	protected void signOut() {
@@ -123,44 +110,25 @@ public abstract class BriarActivity extends BaseActivity {
 	}
 
 	private void startExitActivity() {
-		runOnUiThread(new Runnable() {
-			@Override
-			public void run() {
-				Intent intent = new Intent(BriarActivity.this,
-						ExitActivity.class);
-				intent.addFlags(FLAG_ACTIVITY_NEW_TASK
-						| FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
-						| FLAG_ACTIVITY_NO_ANIMATION);
-				if (Build.VERSION.SDK_INT >= 11)
-					intent.addFlags(FLAG_ACTIVITY_CLEAR_TASK);
-				startActivity(intent);
-			}
-		});
+		Intent intent = new Intent(BriarActivity.this,
+				ExitActivity.class);
+		intent.addFlags(FLAG_ACTIVITY_NEW_TASK
+				| FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+				| FLAG_ACTIVITY_NO_ANIMATION);
+		if (Build.VERSION.SDK_INT >= 11)
+			intent.addFlags(FLAG_ACTIVITY_CLEAR_TASK);
+		startActivity(intent);
 	}
 
 	private void finishAndExit() {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				if (Build.VERSION.SDK_INT >= 21) finishAndRemoveTask();
-				else finish();
-				LOG.info("Exiting");
-				System.exit(0);
-			}
-		});
+		if (Build.VERSION.SDK_INT >= 21) finishAndRemoveTask();
+		else finish();
+		LOG.info("Exiting");
+		System.exit(0);
 	}
 
 	public void runOnDbThread(final Runnable task) {
-		dbExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					lifecycleManager.waitForDatabase();
-					task.run();
-				} catch (InterruptedException e) {
-					LOG.warning("Interrupted while waiting for database");
-					Thread.currentThread().interrupt();
-				}
-			}
-		});
+		briarController.runOnDbThread(task);
 	}
 
 	protected void finishOnUiThread() {
diff --git a/briar-android/src/org/briarproject/android/BriarService.java b/briar-android/src/org/briarproject/android/BriarService.java
index 33d69c8f68..6055c2d691 100644
--- a/briar-android/src/org/briarproject/android/BriarService.java
+++ b/briar-android/src/org/briarproject/android/BriarService.java
@@ -180,7 +180,7 @@ public class BriarService extends Service {
 
 	/** Starts the shutdown process. */
 	public void shutdown() {
-		stopSelf(); // This will call onDestroy()
+		stopSelf(); // This will call onActivityDestroy()
 	}
 
 	public class BriarBinder extends Binder {
diff --git a/briar-android/src/org/briarproject/android/NavDrawerActivity.java b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
index c058bc1968..a5c8f8e290 100644
--- a/briar-android/src/org/briarproject/android/NavDrawerActivity.java
+++ b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
@@ -14,28 +14,19 @@ import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
-import android.widget.Button;
 import android.widget.GridView;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import org.briarproject.R;
-import org.briarproject.android.contact.ContactListFragment;
-import org.briarproject.android.forum.ForumListFragment;
+import org.briarproject.android.controller.NavDrawerController;
+import org.briarproject.android.controller.ResultHandler;
+import org.briarproject.android.controller.TransportStateListener;
 import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.android.util.CustomAnimations;
 import org.briarproject.api.TransportId;
-import org.briarproject.android.api.ReferenceManager;
 import org.briarproject.api.db.DbException;
-import org.briarproject.api.event.Event;
-import org.briarproject.api.event.EventBus;
-import org.briarproject.api.event.EventListener;
-import org.briarproject.api.event.TransportDisabledEvent;
-import org.briarproject.api.event.TransportEnabledEvent;
-import org.briarproject.api.identity.IdentityManager;
 import org.briarproject.api.identity.LocalAuthor;
-import org.briarproject.api.plugins.Plugin;
-import org.briarproject.api.plugins.PluginManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -43,11 +34,8 @@ import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
-import static java.util.logging.Level.INFO;
-import static java.util.logging.Level.WARNING;
-
 public class NavDrawerActivity extends BriarFragmentActivity implements
-		BaseFragment.BaseFragmentListener, EventListener {
+		BaseFragment.BaseFragmentListener, TransportStateListener {
 
 	public final static String PREF_SEEN_WELCOME_MESSAGE = "welcome_message";
 
@@ -60,14 +48,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 	private ActionBarDrawerToggle drawerToggle;
 
 	@Inject
-	protected ReferenceManager referenceManager;
-	// Fields that are accessed from background threads must be volatile
-	@Inject
-	protected volatile IdentityManager identityManager;
-	@Inject
-	protected PluginManager pluginManager;
-	@Inject
-	protected volatile EventBus eventBus;
+	NavDrawerController controller;
 
 	private Toolbar toolbar;
 	private DrawerLayout drawerLayout;
@@ -106,11 +87,11 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 
 		setContentView(R.layout.activity_nav_drawer);
 
-		toolbar = (Toolbar)findViewById(R.id.toolbar);
-		drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
-		transportsView = (GridView)findViewById(R.id.transportsView);
-		progressTitle = (TextView)findViewById(R.id.title_progress_bar);
-		progressViewGroup = (ViewGroup)findViewById(R.id.container_progress);
+		toolbar = (Toolbar) findViewById(R.id.toolbar);
+		drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+		transportsView = (GridView) findViewById(R.id.transportsView);
+		progressTitle = (TextView) findViewById(R.id.title_progress_bar);
+		progressViewGroup = (ViewGroup) findViewById(R.id.container_progress);
 
 		setSupportActionBar(toolbar);
 		getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@@ -151,22 +132,14 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 	@Override
 	public void onResume() {
 		super.onResume();
-		eventBus.addListener(this);
 		updateTransports();
 	}
 
-	@Override
-	protected void onPause() {
-		super.onPause();
-		eventBus.removeListener(this);
-	}
-
 	private void checkAuthorHandle(Intent intent) {
 		long handle = intent.getLongExtra(KEY_LOCAL_AUTHOR_HANDLE, -1);
 		if (handle != -1) {
+			LocalAuthor a = controller.removeAuthorHandle(handle);
 			// The activity was launched from the setup wizard
-			LocalAuthor a = referenceManager.removeReference(handle,
-					LocalAuthor.class);
 			if (a != null) {
 				showLoadingScreen(true, R.string.progress_title_please_wait);
 				storeLocalAuthor(a);
@@ -185,27 +158,18 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 	}
 
 	private void storeLocalAuthor(final LocalAuthor a) {
-		runOnDbThread(new Runnable() {
-			public void run() {
-				try {
-					long now = System.currentTimeMillis();
-					identityManager.addLocalAuthor(a);
-					long duration = System.currentTimeMillis() - now;
-					if (LOG.isLoggable(INFO))
-						LOG.info("Storing author took " + duration + " ms");
-
-					runOnUiThread(new Runnable() {
-						public void run() {
-							hideLoadingScreen();
-						}
-					});
-
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-			}
-		});
+		controller.storeLocalAuthor(a,
+				new ResultHandler<Void, DbException>() {
+					@Override
+					public void onResult(Void result) {
+						hideLoadingScreen();
+					}
+
+					@Override
+					public void onException(DbException exception) {
+
+					}
+				});
 	}
 
 	public void onNavigationClick(View view) {
@@ -281,24 +245,21 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 
 		Transport tor = new Transport();
 		tor.id = new TransportId("tor");
-		Plugin torPlugin = pluginManager.getPlugin(tor.id);
-		tor.enabled = torPlugin != null && torPlugin.isRunning();
+		tor.enabled = controller.transportRunning(tor.id);
 		tor.iconId = R.drawable.transport_tor;
 		tor.textId = R.string.transport_tor;
 		transports.add(tor);
 
 		Transport bt = new Transport();
 		bt.id = new TransportId("bt");
-		Plugin btPlugin = pluginManager.getPlugin(bt.id);
-		bt.enabled = btPlugin != null && btPlugin.isRunning();
+		bt.enabled = controller.transportRunning(bt.id);
 		bt.iconId = R.drawable.transport_bt;
 		bt.textId = R.string.transport_bt;
 		transports.add(bt);
 
 		Transport lan = new Transport();
 		lan.id = new TransportId("lan");
-		Plugin lanPlugin = pluginManager.getPlugin(lan.id);
-		lan.enabled = lanPlugin != null && lanPlugin.isRunning();
+		lan.enabled = controller.transportRunning(lan.id);
 		lan.iconId = R.drawable.transport_lan;
 		lan.textId = R.string.transport_lan;
 		transports.add(lan);
@@ -365,27 +326,14 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 	private void updateTransports() {
 		if (transports == null || transportsAdapter == null) return;
 		for (Transport t : transports) {
-			Plugin plugin = pluginManager.getPlugin(t.id);
-			t.enabled = plugin != null && plugin.isRunning();
+			t.enabled = controller.transportRunning(t.id);
 		}
 		transportsAdapter.notifyDataSetChanged();
 	}
 
 	@Override
-	public void eventOccurred(Event e) {
-		if (e instanceof TransportEnabledEvent) {
-			TransportId id = ((TransportEnabledEvent) e).getTransportId();
-			if (LOG.isLoggable(INFO)) {
-				LOG.info("TransportEnabledEvent: " + id.getString());
-			}
-			setTransport(id, true);
-		} else if (e instanceof TransportDisabledEvent) {
-			TransportId id = ((TransportDisabledEvent) e).getTransportId();
-			if (LOG.isLoggable(INFO)) {
-				LOG.info("TransportDisabledEvent: " + id.getString());
-			}
-			setTransport(id, false);
-		}
+	public void stateUpdate(TransportId id, boolean enabled) {
+		setTransport(id, enabled);
 	}
 
 	private static class Transport {
diff --git a/briar-android/src/org/briarproject/android/PasswordActivity.java b/briar-android/src/org/briarproject/android/PasswordActivity.java
index 34dde0fb14..9f004527a6 100644
--- a/briar-android/src/org/briarproject/android/PasswordActivity.java
+++ b/briar-android/src/org/briarproject/android/PasswordActivity.java
@@ -16,10 +16,10 @@ import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
 import org.briarproject.R;
-import org.briarproject.android.event.PasswordValidateEvent;
-import org.briarproject.android.helper.PasswordHelper;
+import org.briarproject.android.controller.EncryptedKeyNullException;
+import org.briarproject.android.controller.PasswordController;
+import org.briarproject.android.controller.ResultHandler;
 import org.briarproject.android.util.AndroidUtils;
-import org.briarproject.api.event.Event;
 
 import javax.inject.Inject;
 
@@ -36,7 +36,7 @@ public class PasswordActivity extends BaseActivity {
 	private EditText password;
 
 	@Inject
-	PasswordHelper passwordHelper;
+	PasswordController passwordHelper;
 
 	@Override
 	public void onCreate(Bundle state) {
@@ -125,22 +125,23 @@ public class PasswordActivity extends BaseActivity {
 		hideSoftKeyboard(password);
 		signInButton.setVisibility(INVISIBLE);
 		progress.setVisibility(VISIBLE);
-		passwordHelper.validatePassword(password.getText().toString());
-	}
+		passwordHelper.validatePassword(password.getText().toString(),
+				new ResultHandler<Boolean, EncryptedKeyNullException>() {
+					@Override
+					public void onResult(Boolean result) {
+						if (result != null && result) {
+							setResult(RESULT_OK);
+							finish();
+						} else {
+							tryAgain();
+						}
+					}
 
-	@Override
-	public void eventOccurred(Event e) {
-		super.eventOccurred(e);
-		if (e instanceof PasswordValidateEvent) {
-			boolean validated = ((PasswordValidateEvent)e).passwordValidated();
-			if (validated) {
-				setResult(RESULT_OK);
-				finish();
-			}
-			else {
-				tryAgain();
-			}
-		}
+					@Override
+					public void onException(EncryptedKeyNullException e) {
+						// TODO ?
+					}
+				});
 	}
 
 	private void tryAgain() {
diff --git a/briar-android/src/org/briarproject/android/SetupActivity.java b/briar-android/src/org/briarproject/android/SetupActivity.java
index d50e38b210..1aaba344c0 100644
--- a/briar-android/src/org/briarproject/android/SetupActivity.java
+++ b/briar-android/src/org/briarproject/android/SetupActivity.java
@@ -15,24 +15,12 @@ import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
 import org.briarproject.R;
-import org.briarproject.android.event.LocalAuthorCreatedEvent;
-import org.briarproject.android.helper.SetupHelper;
+import org.briarproject.android.controller.ResultHandler;
+import org.briarproject.android.controller.SetupController;
 import org.briarproject.android.util.AndroidUtils;
 import org.briarproject.android.util.StrengthMeter;
-import org.briarproject.android.api.ReferenceManager;
-import org.briarproject.api.crypto.CryptoComponent;
-import org.briarproject.api.crypto.CryptoExecutor;
-import org.briarproject.api.crypto.KeyPair;
-import org.briarproject.api.crypto.PasswordStrengthEstimator;
-import org.briarproject.api.crypto.SecretKey;
-import org.briarproject.api.db.DatabaseConfig;
-import org.briarproject.api.event.Event;
-import org.briarproject.api.identity.AuthorFactory;
-import org.briarproject.api.identity.LocalAuthor;
-import org.briarproject.util.StringUtils;
 
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
+import org.briarproject.util.StringUtils;
 
 import javax.inject.Inject;
 
@@ -40,7 +28,6 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static java.util.logging.Level.INFO;
 import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS;
 import static org.briarproject.api.crypto.PasswordStrengthEstimator.WEAK;
 import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
@@ -49,7 +36,7 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
 		OnEditorActionListener {
 
 	@Inject
-	SetupHelper setupHelper;
+	SetupController setupController;
 
 	TextInputLayout nicknameEntryWrapper;
 	TextInputLayout passwordEntryWrapper;
@@ -120,8 +107,7 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
 		String firstPassword = passwordEntry.getText().toString();
 		String secondPassword = passwordConfirmation.getText().toString();
 		boolean passwordsMatch = firstPassword.equals(secondPassword);
-//		float strength = strengthEstimator.estimateStrength(firstPassword);
-		float strength = setupHelper.estimatePasswordStrength(firstPassword);
+		float strength = setupController.estimatePasswordStrength(firstPassword);
 		strengthMeter.setStrength(strength);
 		AndroidUtils.setError(nicknameEntryWrapper,
 				getString(R.string.name_too_long),
@@ -148,19 +134,22 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
 		progress.setVisibility(VISIBLE);
 		final String nickname = nicknameEntry.getText().toString();
 		final String password = passwordEntry.getText().toString();
-		setupHelper.createIdentity(nickname, password);
-	}
-
-	@Override
-	public void eventOccurred(Event e) {
-		super.eventOccurred(e);
-		if (e instanceof LocalAuthorCreatedEvent) {
-			long handle = ((LocalAuthorCreatedEvent)e).getAuthorHandle();
-			showDashboard(handle);
-		}
+		setupController.createIdentity(nickname, password,
+				new ResultHandler<Long, RuntimeException>() {
+					@Override
+					public void onResult(Long result) {
+						if (result != null)
+							showMain(result);
+					}
+
+					@Override
+					public void onException(RuntimeException exception) {
+
+					}
+				});
 	}
 
-	private void showDashboard(final long handle) {
+	private void showMain(final long handle) {
 		Intent i = new Intent(SetupActivity.this,
 				NavDrawerActivity.class);
 		i.putExtra(BriarActivity.KEY_LOCAL_AUTHOR_HANDLE, handle);
diff --git a/briar-android/src/org/briarproject/android/SplashScreenActivity.java b/briar-android/src/org/briarproject/android/SplashScreenActivity.java
index 0439159703..2064c67d6f 100644
--- a/briar-android/src/org/briarproject/android/SplashScreenActivity.java
+++ b/briar-android/src/org/briarproject/android/SplashScreenActivity.java
@@ -9,7 +9,7 @@ import android.os.StrictMode.VmPolicy;
 import android.support.v7.preference.PreferenceManager;
 
 import org.briarproject.R;
-import org.briarproject.android.helper.ConfigHelper;
+import org.briarproject.android.controller.ConfigController;
 import org.briarproject.android.util.AndroidUtils;
 
 import java.util.logging.Logger;
@@ -28,7 +28,7 @@ public class SplashScreenActivity extends BaseActivity {
 	private static final long EXPIRY_DATE = 1464735600 * 1000L;
 
 	@Inject
-	ConfigHelper configHelper;
+	ConfigController configController;
 
 	public SplashScreenActivity() {
 		Logger.getLogger("").setLevel(DEFAULT_LOG_LEVEL);
@@ -62,10 +62,10 @@ public class SplashScreenActivity extends BaseActivity {
 			LOG.info("Expired");
 			startActivity(new Intent(this, ExpiredActivity.class));
 		} else {
-			if (configHelper.initialized()) {
+			if (configController.initialized()) {
 				startActivity(new Intent(this, NavDrawerActivity.class));
 			} else {
-				configHelper.clearPrefs();
+				configController.clearPrefs();
 				AndroidUtils.deleteAppData(this);
 				startActivity(new Intent(this, SetupActivity.class));
 			}
diff --git a/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java b/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java
new file mode 100644
index 0000000000..68b15592ce
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/ActivityLifecycleController.java
@@ -0,0 +1,11 @@
+package org.briarproject.android.controller;
+
+public interface ActivityLifecycleController {
+	void onActivityCreate();
+
+	void onActivityResume();
+
+	void onActivityPause();
+
+	void onActivityDestroy();
+}
diff --git a/briar-android/src/org/briarproject/android/controller/BriarController.java b/briar-android/src/org/briarproject/android/controller/BriarController.java
new file mode 100644
index 0000000000..edb035cb32
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/BriarController.java
@@ -0,0 +1,14 @@
+package org.briarproject.android.controller;
+
+
+public interface BriarController extends ActivityLifecycleController {
+	void runOnDbThread(final Runnable task);
+
+	void startAndBindService();
+
+	void unbindService();
+
+	boolean encryptionKey();
+
+	void signOut(ResultHandler<Void, RuntimeException> eventHandler);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/BriarControllerImp.java b/briar-android/src/org/briarproject/android/controller/BriarControllerImp.java
new file mode 100644
index 0000000000..789b27af46
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/BriarControllerImp.java
@@ -0,0 +1,123 @@
+package org.briarproject.android.controller;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.IBinder;
+import android.support.annotation.CallSuper;
+
+import org.briarproject.android.BriarService;
+import org.briarproject.android.BriarService.BriarServiceConnection;
+import org.briarproject.api.db.DatabaseConfig;
+import org.briarproject.api.db.DatabaseExecutor;
+import org.briarproject.api.lifecycle.LifecycleManager;
+
+import java.util.concurrent.Executor;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+
+public class BriarControllerImp implements BriarController {
+
+	private static final Logger LOG =
+			Logger.getLogger(BriarControllerImp.class.getName());
+
+	@Inject
+	protected BriarServiceConnection serviceConnection;
+	@Inject
+	protected DatabaseConfig databaseConfig;
+	// Fields that are accessed from background threads must be volatile
+	@Inject
+	@DatabaseExecutor
+	protected volatile Executor dbExecutor;
+	@Inject
+	protected volatile LifecycleManager lifecycleManager;
+	@Inject
+	protected Activity activity;
+
+	private boolean bound = false;
+
+	@Inject
+	public BriarControllerImp() {
+
+	}
+
+	@Override
+	@CallSuper
+	public void onActivityCreate() {
+		if (databaseConfig.getEncryptionKey() != null) startAndBindService();
+	}
+
+	@Override
+	@CallSuper
+	public void onActivityResume() {
+	}
+
+	@Override
+	@CallSuper
+	public void onActivityPause() {
+	}
+
+	@Override
+	@CallSuper
+	public void onActivityDestroy() {
+		unbindService();
+	}
+
+	public void startAndBindService() {
+		activity.startService(new Intent(activity, BriarService.class));
+		bound = activity.bindService(new Intent(activity, BriarService.class),
+				serviceConnection, 0);
+	}
+
+	@Override
+	public boolean encryptionKey() {
+		return databaseConfig.getEncryptionKey() != null;
+	}
+
+	@Override
+	public void signOut(final ResultHandler<Void, RuntimeException> eventHandler) {
+		new Thread() {
+			@Override
+			public void run() {
+				try {
+					// Wait for the service to finish starting up
+					IBinder binder = serviceConnection.waitForBinder();
+					BriarService service = ((BriarService.BriarBinder) binder).getService();
+					service.waitForStartup();
+					// Shut down the service and wait for it to shut down
+					LOG.info("Shutting down service");
+					service.shutdown();
+					service.waitForShutdown();
+				} catch (InterruptedException e) {
+					LOG.warning("Interrupted while waiting for service");
+					Thread.currentThread().interrupt();
+				}
+				activity.runOnUiThread(new Runnable() {
+					@Override
+					public void run() {
+						eventHandler.onResult(null);
+					}
+				});
+			}
+		}.start();
+	}
+
+	public void unbindService() {
+		if (bound) activity.unbindService(serviceConnection);
+	}
+
+	public void runOnDbThread(final Runnable task) {
+		dbExecutor.execute(new Runnable() {
+			public void run() {
+				try {
+					lifecycleManager.waitForDatabase();
+					task.run();
+				} catch (InterruptedException e) {
+					LOG.warning("Interrupted while waiting for database");
+					Thread.currentThread().interrupt();
+				}
+			}
+		});
+	}
+
+}
diff --git a/briar-android/src/org/briarproject/android/helper/ConfigHelper.java b/briar-android/src/org/briarproject/android/controller/ConfigController.java
similarity index 50%
rename from briar-android/src/org/briarproject/android/helper/ConfigHelper.java
rename to briar-android/src/org/briarproject/android/controller/ConfigController.java
index 0fe70579da..cddbc1bc68 100644
--- a/briar-android/src/org/briarproject/android/helper/ConfigHelper.java
+++ b/briar-android/src/org/briarproject/android/controller/ConfigController.java
@@ -1,6 +1,6 @@
-package org.briarproject.android.helper;
+package org.briarproject.android.controller;
 
-public interface ConfigHelper {
+public interface ConfigController {
 	String getEncryptedDatabaseKey();
 
 	void clearPrefs();
diff --git a/briar-android/src/org/briarproject/android/helper/ConfigHelperImp.java b/briar-android/src/org/briarproject/android/controller/ConfigControllerImp.java
similarity index 83%
rename from briar-android/src/org/briarproject/android/helper/ConfigHelperImp.java
rename to briar-android/src/org/briarproject/android/controller/ConfigControllerImp.java
index ca818148a0..d37ab8f1b2 100644
--- a/briar-android/src/org/briarproject/android/helper/ConfigHelperImp.java
+++ b/briar-android/src/org/briarproject/android/controller/ConfigControllerImp.java
@@ -1,4 +1,4 @@
-package org.briarproject.android.helper;
+package org.briarproject.android.controller;
 
 import android.content.SharedPreferences;
 
@@ -6,7 +6,7 @@ import org.briarproject.api.db.DatabaseConfig;
 
 import javax.inject.Inject;
 
-public class ConfigHelperImp implements ConfigHelper {
+public class ConfigControllerImp implements ConfigController {
 
 	private final static String PREF_DB_KEY = "key";
 
@@ -16,7 +16,7 @@ public class ConfigHelperImp implements ConfigHelper {
 	protected volatile DatabaseConfig databaseConfig;
 
 	@Inject
-	public ConfigHelperImp() {
+	public ConfigControllerImp() {
 
 	}
 
diff --git a/briar-android/src/org/briarproject/android/controller/EncryptedKeyNullException.java b/briar-android/src/org/briarproject/android/controller/EncryptedKeyNullException.java
new file mode 100644
index 0000000000..3da38efa49
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/EncryptedKeyNullException.java
@@ -0,0 +1,9 @@
+package org.briarproject.android.controller;
+
+public class EncryptedKeyNullException extends NullPointerException {
+
+	@Override
+	public String toString() {
+		return "Encrypted key can't be null";
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/controller/NavDrawerController.java b/briar-android/src/org/briarproject/android/controller/NavDrawerController.java
new file mode 100644
index 0000000000..13dfbcc29d
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/NavDrawerController.java
@@ -0,0 +1,16 @@
+package org.briarproject.android.controller;
+
+import org.briarproject.api.TransportId;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.identity.LocalAuthor;
+
+public interface NavDrawerController extends BriarController {
+	void setTransportListener(TransportStateListener transportListener);
+
+	boolean transportRunning(TransportId transportId);
+
+	void storeLocalAuthor(LocalAuthor author,
+			ResultHandler<Void, DbException> resultHandler);
+
+	LocalAuthor removeAuthorHandle(long handle);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImp.java b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImp.java
new file mode 100644
index 0000000000..a86b7231d7
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImp.java
@@ -0,0 +1,159 @@
+package org.briarproject.android.controller;
+
+import android.app.Activity;
+
+import org.briarproject.android.api.ReferenceManager;
+import org.briarproject.api.TransportId;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.event.Event;
+import org.briarproject.api.event.EventBus;
+import org.briarproject.api.event.EventListener;
+import org.briarproject.api.event.TransportDisabledEvent;
+import org.briarproject.api.event.TransportEnabledEvent;
+import org.briarproject.api.identity.IdentityManager;
+import org.briarproject.api.identity.LocalAuthor;
+import org.briarproject.api.plugins.Plugin;
+import org.briarproject.api.plugins.PluginManager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
+
+public class NavDrawerControllerImp extends BriarControllerImp
+		implements NavDrawerController, EventListener {
+
+	private static final Logger LOG =
+			Logger.getLogger(NavDrawerControllerImp.class.getName());
+
+	@Inject
+	protected ReferenceManager referenceManager;
+	@Inject
+	protected volatile IdentityManager identityManager;
+	@Inject
+	protected PluginManager pluginManager;
+	@Inject
+	protected volatile EventBus eventBus;
+	@Inject
+	protected Activity activity;
+
+	private List<Plugin> transports = new ArrayList<Plugin>();
+
+	private TransportStateListener transportStateListener;
+
+	@Inject
+	public NavDrawerControllerImp() {
+
+	}
+
+	@Override
+	public void onActivityCreate() {
+		super.onActivityCreate();
+		initializeTransports();
+	}
+
+	@Override
+	public void onActivityResume() {
+		super.onActivityResume();
+		eventBus.addListener(this);
+	}
+
+	@Override
+	public void onActivityPause() {
+		super.onActivityPause();
+		eventBus.removeListener(this);
+	}
+
+	@Override
+	public void eventOccurred(Event e) {
+		if (e instanceof TransportEnabledEvent) {
+			TransportId id = ((TransportEnabledEvent) e).getTransportId();
+			if (LOG.isLoggable(INFO)) {
+				LOG.info("TransportEnabledEvent: " + id.getString());
+			}
+			transportStateUpdate(id, true);
+		} else if (e instanceof TransportDisabledEvent) {
+			TransportId id = ((TransportDisabledEvent) e).getTransportId();
+			if (LOG.isLoggable(INFO)) {
+				LOG.info("TransportDisabledEvent: " + id.getString());
+			}
+			transportStateUpdate(id, false);
+		}
+	}
+
+	private void transportStateUpdate(final TransportId id, final boolean enabled) {
+		activity.runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				if (transportStateListener != null) {
+					transportStateListener.stateUpdate(id, enabled);
+				}
+			}
+		});
+	}
+
+	private void initializeTransports() {
+		transports.clear();
+		transports.add(pluginManager.getPlugin(new TransportId("tor")));
+		transports.add(pluginManager.getPlugin(new TransportId("bt")));
+		transports.add(pluginManager.getPlugin(new TransportId("lan")));
+	}
+
+	@Override
+	public void setTransportListener(TransportStateListener transportListener) {
+		this.transportStateListener = transportListener;
+	}
+
+	@Override
+	public boolean transportRunning(TransportId transportId) {
+		for (Plugin transport : transports) {
+			if (transport.getId().equals(transportId)) {
+				return transport.isRunning();
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public void storeLocalAuthor(final LocalAuthor author,
+			final ResultHandler<Void, DbException> resultHandler) {
+		runOnDbThread(new Runnable() {
+			public void run() {
+				try {
+					long now = System.currentTimeMillis();
+					identityManager.addLocalAuthor(author);
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO))
+						LOG.info("Storing author took " + duration + " ms");
+					activity.runOnUiThread(new Runnable() {
+						@Override
+						public void run() {
+							resultHandler.onResult(null);
+						}
+					});
+				} catch (final DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+
+					activity.runOnUiThread(new Runnable() {
+						@Override
+						public void run() {
+							resultHandler.onException(e);
+						}
+					});
+				}
+			}
+		});
+	}
+
+	@Override
+	public LocalAuthor removeAuthorHandle(long handle) {
+		return referenceManager.removeReference(handle,
+				LocalAuthor.class);
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/controller/PasswordController.java b/briar-android/src/org/briarproject/android/controller/PasswordController.java
new file mode 100644
index 0000000000..b40ddb6703
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/PasswordController.java
@@ -0,0 +1,6 @@
+package org.briarproject.android.controller;
+
+public interface PasswordController extends ConfigController {
+	void validatePassword(String password,
+			ResultHandler<Boolean, EncryptedKeyNullException> resultHandler);
+}
diff --git a/briar-android/src/org/briarproject/android/helper/PasswordHelperImp.java b/briar-android/src/org/briarproject/android/controller/PasswordControllerImp.java
similarity index 57%
rename from briar-android/src/org/briarproject/android/helper/PasswordHelperImp.java
rename to briar-android/src/org/briarproject/android/controller/PasswordControllerImp.java
index f999337aef..ed86bb9bd1 100644
--- a/briar-android/src/org/briarproject/android/helper/PasswordHelperImp.java
+++ b/briar-android/src/org/briarproject/android/controller/PasswordControllerImp.java
@@ -1,10 +1,7 @@
-package org.briarproject.android.helper;
+package org.briarproject.android.controller;
 
 import android.app.Activity;
 
-import org.briarproject.android.event.AppBus;
-import org.briarproject.android.event.ErrorEvent;
-import org.briarproject.android.event.PasswordValidateEvent;
 import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.crypto.CryptoExecutor;
 import org.briarproject.api.crypto.SecretKey;
@@ -14,8 +11,8 @@ import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
-public class PasswordHelperImp extends ConfigHelperImp
-		implements PasswordHelper {
+public class PasswordControllerImp extends ConfigControllerImp
+		implements PasswordController {
 
 	@Inject
 	@CryptoExecutor
@@ -24,38 +21,38 @@ public class PasswordHelperImp extends ConfigHelperImp
 	protected CryptoComponent crypto;
 	@Inject
 	protected Activity activity;
-	@Inject
-	protected AppBus appBus;
 
 	@Inject
-	public PasswordHelperImp() {
+	public PasswordControllerImp() {
 
 	}
 
 	@Override
-	public void validatePassword(final String password) {
+	public void validatePassword(final String password,
+			final ResultHandler<Boolean, EncryptedKeyNullException> resultHandler) {
 		final byte[] encrypted = getEncryptedKey();
 		if (encrypted == null) {
-			appBus.broadcast(new ErrorEvent());
+			resultHandler.onException(new EncryptedKeyNullException());
 		}
 		cryptoExecutor.execute(new Runnable() {
 			public void run() {
 				byte[] key = crypto.decryptWithPassword(encrypted, password);
 				if (key == null) {
-					onPasswordValidated(false);
+					onPasswordValidated(false, resultHandler);
 				} else {
 					databaseConfig.setEncryptionKey(new SecretKey(key));
-					onPasswordValidated(true);
+					onPasswordValidated(true, resultHandler);
 				}
 			}
 		});
 	}
 
-	private void onPasswordValidated(final boolean validated) {
+	private void onPasswordValidated(final boolean validated,
+			final ResultHandler<Boolean, EncryptedKeyNullException> resultHandler) {
 		activity.runOnUiThread(new Runnable() {
 			@Override
 			public void run() {
-				appBus.broadcast(new PasswordValidateEvent(validated));
+				resultHandler.onResult(validated);
 			}
 		});
 	}
@@ -63,6 +60,6 @@ public class PasswordHelperImp extends ConfigHelperImp
 
 	private byte[] getEncryptedKey() {
 		String hex = getEncryptedDatabaseKey();
-		return hex == null? null : StringUtils.fromHexString(hex);
+		return hex == null ? null : StringUtils.fromHexString(hex);
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/controller/ResultHandler.java b/briar-android/src/org/briarproject/android/controller/ResultHandler.java
new file mode 100644
index 0000000000..5f98763aae
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/ResultHandler.java
@@ -0,0 +1,6 @@
+package org.briarproject.android.controller;
+
+public interface ResultHandler<R, E> {
+	void onResult(R result);
+	void onException(E exception);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/SetupController.java b/briar-android/src/org/briarproject/android/controller/SetupController.java
new file mode 100644
index 0000000000..884706c3f9
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/SetupController.java
@@ -0,0 +1,8 @@
+package org.briarproject.android.controller;
+
+public interface SetupController {
+	float estimatePasswordStrength(String password);
+
+	void createIdentity(String nickname, String password,
+			ResultHandler<Long, RuntimeException> resultHandler);
+}
diff --git a/briar-android/src/org/briarproject/android/helper/SetupHelperImp.java b/briar-android/src/org/briarproject/android/controller/SetupControllerImp.java
similarity index 83%
rename from briar-android/src/org/briarproject/android/helper/SetupHelperImp.java
rename to briar-android/src/org/briarproject/android/controller/SetupControllerImp.java
index 9015c482f5..312502f422 100644
--- a/briar-android/src/org/briarproject/android/helper/SetupHelperImp.java
+++ b/briar-android/src/org/briarproject/android/controller/SetupControllerImp.java
@@ -1,11 +1,10 @@
-package org.briarproject.android.helper;
+package org.briarproject.android.controller;
 
 import android.app.Activity;
 import android.content.SharedPreferences;
 
+import org.briarproject.android.BaseActivity;
 import org.briarproject.android.api.ReferenceManager;
-import org.briarproject.android.event.AppBus;
-import org.briarproject.android.event.LocalAuthorCreatedEvent;
 import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.crypto.CryptoExecutor;
 import org.briarproject.api.crypto.KeyPair;
@@ -23,10 +22,10 @@ import javax.inject.Inject;
 
 import static java.util.logging.Level.INFO;
 
-public class SetupHelperImp implements SetupHelper {
+public class SetupControllerImp implements SetupController {
 
 	private static final Logger LOG =
-			Logger.getLogger(SetupHelperImp.class.getName());
+			Logger.getLogger(SetupControllerImp.class.getName());
 
 	private final static String PREF_DB_KEY = "key";
 
@@ -45,16 +44,13 @@ public class SetupHelperImp implements SetupHelper {
 	protected volatile AuthorFactory authorFactory;
 	@Inject
 	protected volatile ReferenceManager referenceManager;
-
 	@Inject
 	protected Activity activity;
 	@Inject
 	protected SharedPreferences briarPrefs;
-	@Inject
-	protected AppBus appBus;
 
 	@Inject
-	public SetupHelperImp() {
+	public SetupControllerImp() {
 
 	}
 
@@ -86,7 +82,8 @@ public class SetupHelperImp implements SetupHelper {
 	}
 
 	@Override
-	public void createIdentity(final String nickname, final String password) {
+	public void createIdentity(final String nickname, final String password,
+			final ResultHandler<Long, RuntimeException> resultHandler) {
 		cryptoExecutor.execute(new Runnable() {
 			public void run() {
 				SecretKey key = crypto.generateSecretKey();
@@ -94,18 +91,20 @@ public class SetupHelperImp implements SetupHelper {
 				String hex = encryptDatabaseKey(key, password);
 				storeEncryptedDatabaseKey(hex);
 				final LocalAuthor localAuthor = createLocalAuthor(nickname);
-				onIdentityCreated(referenceManager.putReference(localAuthor,
-						LocalAuthor.class));
+				long handle = referenceManager.putReference(localAuthor,
+						LocalAuthor.class);
+				onIdentityCreated(handle, resultHandler);
 
 			}
 		});
 	}
 
-	private void onIdentityCreated(final long handle) {
+	private void onIdentityCreated(final long handle,
+			final ResultHandler<Long, RuntimeException> resultHandler) {
 		activity.runOnUiThread(new Runnable() {
 			@Override
 			public void run() {
-				appBus.broadcast(new LocalAuthorCreatedEvent(handle));
+				resultHandler.onResult(handle);
 			}
 		});
 	}
diff --git a/briar-android/src/org/briarproject/android/controller/TransportStateListener.java b/briar-android/src/org/briarproject/android/controller/TransportStateListener.java
new file mode 100644
index 0000000000..0a00c0f7dc
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/TransportStateListener.java
@@ -0,0 +1,7 @@
+package org.briarproject.android.controller;
+
+import org.briarproject.api.TransportId;
+
+public interface TransportStateListener {
+	void stateUpdate(TransportId id, boolean enabled);
+}
diff --git a/briar-android/src/org/briarproject/android/event/AppBus.java b/briar-android/src/org/briarproject/android/event/AppBus.java
deleted file mode 100644
index 08008e28ee..0000000000
--- a/briar-android/src/org/briarproject/android/event/AppBus.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.briarproject.android.event;
-
-import org.briarproject.api.event.EventBus;
-
-public interface AppBus extends EventBus{
-}
diff --git a/briar-android/src/org/briarproject/android/event/AppBusImp.java b/briar-android/src/org/briarproject/android/event/AppBusImp.java
deleted file mode 100644
index f193e13101..0000000000
--- a/briar-android/src/org/briarproject/android/event/AppBusImp.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.briarproject.android.event;
-
-
-import org.briarproject.api.event.Event;
-import org.briarproject.api.event.EventListener;
-
-import java.util.Collection;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-public class AppBusImp implements AppBus {
-	private final Collection<EventListener> listeners =
-			new CopyOnWriteArrayList<EventListener>();
-
-	public void addListener(EventListener l) {
-		listeners.add(l);
-	}
-
-	public void removeListener(EventListener l) {
-		listeners.remove(l);
-	}
-
-	public void broadcast(Event e) {
-		for (EventListener l : listeners) l.eventOccurred(e);
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/event/ErrorEvent.java b/briar-android/src/org/briarproject/android/event/ErrorEvent.java
deleted file mode 100644
index f326fd575d..0000000000
--- a/briar-android/src/org/briarproject/android/event/ErrorEvent.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.briarproject.android.event;
-
-import org.briarproject.api.event.Event;
-
-public class ErrorEvent extends Event {
-
-	public ErrorEvent() {
-
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/event/LocalAuthorCreatedEvent.java b/briar-android/src/org/briarproject/android/event/LocalAuthorCreatedEvent.java
deleted file mode 100644
index 6a9b2e2560..0000000000
--- a/briar-android/src/org/briarproject/android/event/LocalAuthorCreatedEvent.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.briarproject.android.event;
-
-import org.briarproject.api.event.Event;
-
-public class LocalAuthorCreatedEvent extends Event {
-
-	private final long handle;
-
-	public LocalAuthorCreatedEvent(long handle) {
-		this.handle = handle;
-	}
-
-	public long getAuthorHandle() {
-		return handle;
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/event/PasswordValidateEvent.java b/briar-android/src/org/briarproject/android/event/PasswordValidateEvent.java
deleted file mode 100644
index 35a3552821..0000000000
--- a/briar-android/src/org/briarproject/android/event/PasswordValidateEvent.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.briarproject.android.event;
-
-import org.briarproject.api.event.Event;
-
-public class PasswordValidateEvent extends Event {
-
-	private final boolean passwordValidated;
-
-	public PasswordValidateEvent(boolean passwordValidated) {
-		this.passwordValidated = passwordValidated;
-	}
-
-	public boolean passwordValidated() {
-		return passwordValidated;
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/helper/PasswordHelper.java b/briar-android/src/org/briarproject/android/helper/PasswordHelper.java
deleted file mode 100644
index 00aeb3da6d..0000000000
--- a/briar-android/src/org/briarproject/android/helper/PasswordHelper.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.briarproject.android.helper;
-
-public interface PasswordHelper extends ConfigHelper {
-	void validatePassword(String password);
-}
diff --git a/briar-android/src/org/briarproject/android/helper/SetupHelper.java b/briar-android/src/org/briarproject/android/helper/SetupHelper.java
deleted file mode 100644
index 329b8b2106..0000000000
--- a/briar-android/src/org/briarproject/android/helper/SetupHelper.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package org.briarproject.android.helper;
-
-public interface SetupHelper {
-	float estimatePasswordStrength(String password);
-	void createIdentity(String nickname, String password);
-}
diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
index 66a5c63eaa..332efc6555 100644
--- a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
+++ b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
@@ -287,7 +287,7 @@ implements InvitationListener {
 				localInvitationCode, code);
 		taskHandle = referenceManager.putReference(task, InvitationTask.class);
 		task.addListener(AddContactActivity.this);
-		// Add a second listener so we can remove the first in onDestroy(),
+		// Add a second listener so we can remove the first in onActivityDestroy(),
 		// allowing the activity to be garbage collected if it's destroyed
 		task.addListener(new ReferenceCleaner(referenceManager, taskHandle));
 		task.connect();
diff --git a/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java b/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java
index 03198cf482..bdb0377850 100644
--- a/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java
+++ b/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java
@@ -8,11 +8,9 @@ import android.os.Bundle;
 import android.support.v7.preference.PreferenceManager;
 
 import org.briarproject.android.ActivityComponent;
-import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarActivity;
-import org.briarproject.android.helper.ConfigHelper;
+import org.briarproject.android.controller.ConfigController;
 import org.briarproject.android.util.AndroidUtils;
-import org.briarproject.api.db.DatabaseConfig;
 import org.iilab.IilabEngineeringRSA2048Pin;
 
 import java.util.logging.Logger;
@@ -32,7 +30,7 @@ public class PanicResponderActivity extends BriarActivity {
 
 	private static final Logger LOG =
 			Logger.getLogger(PanicResponderActivity.class.getName());
-	@Inject protected ConfigHelper configHelper;
+	@Inject protected ConfigController configController;
 
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
@@ -108,7 +106,7 @@ public class PanicResponderActivity extends BriarActivity {
 	private void deleteAllData() {
 		androidExecutor.execute(new Runnable() {
 			public void run() {
-				configHelper.clearPrefs();
+				configController.clearPrefs();
 				// TODO somehow delete/shred the database more thoroughly
 				AndroidUtils.deleteAppData(PanicResponderActivity.this);
 				PanicResponder.deleteAllAppData(PanicResponderActivity.this);
-- 
GitLab