diff --git a/briar-android/src/org/briarproject/android/ActivityModule.java b/briar-android/src/org/briarproject/android/ActivityModule.java
index 1f398b8e57aa052f9beb8bed6179b020ea7e5853..33e291abc37dd07b34e0fd141a09767f1f383018 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 f482e52981752f83f01ec2536e761ce2bb6f8246..c5396da798e8ffcffb34ef4ace5bc2084307690b 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 213088daa814a0abc17416f60c297d2b819a7a94..1bbbc6fdec441dd06721f08880999d1a693a3abd 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 8043b1a14038cb473963917a06bfe2e427b97edc..a61e4059dca618d1d152236a7d982eae9e60fa6f 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 33d69c8f68e2a6ed7144d4e69014b51b7f783531..6055c2d691634bd3318b5396a76d757bea7d4409 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 c058bc19685f83a8038a0292eb494904fd5113fc..a5c8f8e29034a678a74f283e677455ae88e8b6c9 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 34dde0fb142e6c66e0944fc13ff2f88785a23df9..9f004527a628ce978f29b750f24079b21a174e6b 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 d50e38b210fc5f5d02cdc9c3a38397c5c563f53f..1aaba344c06d3eee69ee9735f4a167c447ca6ece 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 0439159703788cd923a3484da48e940339aa33ba..2064c67d6fbd18ddf0713f0e51d0ae2c51f6fc6f 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 0000000000000000000000000000000000000000..68b15592ce12a740f3ffbd4c357501269136d57e
--- /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 0000000000000000000000000000000000000000..edb035cb32f2ad70746b9403629601ceec40843b
--- /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 0000000000000000000000000000000000000000..789b27af46b8857e2d4fffd8efd5901edf473314
--- /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 0fe70579da1f637cea3b6a5ddadb69aa20620ac7..cddbc1bc688e98e21cc7e562175e91d073c52698 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 ca818148a06d1ce66c326779a9eeae1814d384af..d37ab8f1b2f22ae71268b5f4bcdbe8db59b51616 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 0000000000000000000000000000000000000000..3da38efa493e4cf27937315e1c0c253ee793df8a
--- /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 0000000000000000000000000000000000000000..13dfbcc29d63f052a702aeb2540236bb4beb79f9
--- /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 0000000000000000000000000000000000000000..a86b7231d773fde5beb6336ec2952c785857017f
--- /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 0000000000000000000000000000000000000000..b40ddb6703eef92961874f3d2a0bb5fa379c9e68
--- /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 f999337aef7da208c991ff0eaf086a0712f36093..ed86bb9bd11a8be8f4edb1d91e253f0ef2b415a0 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 0000000000000000000000000000000000000000..5f98763aaecdbdba5953261ead7d0b407eec5dd1
--- /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 0000000000000000000000000000000000000000..884706c3f9c629d11569df78de24a0dc6b286f4d
--- /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 9015c482f567e8de89c4c5514b014be9bcbc1519..312502f42247b07427c409893405312988529e22 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 0000000000000000000000000000000000000000..0a00c0f7dc0c73d846e3222884b7d37311fde601
--- /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 08008e28ee5dd18ad205350d1b9ef1ec1290e96c..0000000000000000000000000000000000000000
--- 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 f193e13101018e9268c7ae99fda97a0e782f8511..0000000000000000000000000000000000000000
--- 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 f326fd575d6e1437653cd3c04a3b4aca0d6a51ab..0000000000000000000000000000000000000000
--- 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 6a9b2e2560a19c6deec81b5123cbb95fd99dbcf2..0000000000000000000000000000000000000000
--- 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 35a35528212af21538076364c8d9d3ac85ce7921..0000000000000000000000000000000000000000
--- 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 00aeb3da6d43c591c631def398472d16fa4218ea..0000000000000000000000000000000000000000
--- 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 329b8b2106d00851e29ce76c291b37b6d0561b25..0000000000000000000000000000000000000000
--- 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 66a5c63eaa4730bbaf0b04904b2d70e549e54e22..332efc6555b8d45baba7f9bd3be5c7e9604d05d6 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 03198cf48280756deee04ebcb8133b3efc95fb33..bdb037785072b8c2d6ee14a9879e045a21ba8b0c 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);