diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml
index 10b50aa4d7fb22e251f1d3a2b0ea5a02744518e1..6901075a358d1da14b42e48c0276d8ce70e0eb9a 100644
--- a/briar-android/AndroidManifest.xml
+++ b/briar-android/AndroidManifest.xml
@@ -29,7 +29,7 @@
 	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 
 	<application
-		android:name=".android.BriarApplication"
+		android:name=".android.BriarApplicationImpl"
 		android:allowBackup="false"
 		android:icon="@drawable/ic_launcher"
 		android:label="@string/app_name"
diff --git a/briar-android/build.gradle b/briar-android/build.gradle
index 6ff778d86d62aa63fe035f7a0f434455f2dea65f..7b8deefc3722575fa5c6c914cb181a7fd84843d3 100644
--- a/briar-android/build.gradle
+++ b/briar-android/build.gradle
@@ -8,6 +8,7 @@ apply plugin: 'de.undercouch.download'
 
 repositories {
 	jcenter()
+	maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
 }
 
 dependencies {
@@ -44,6 +45,18 @@ dependencies {
 	compile 'com.google.zxing:core:3.2.1'
 	apt 'com.google.dagger:dagger-compiler:2.0.2'
 	provided 'javax.annotation:jsr250-api:1.0'
+
+	testCompile 'junit:junit:4.12'
+	testCompile 'net.jodah:concurrentunit:0.4.2'
+	testApt 'com.google.dagger:dagger-compiler:2.0.2'
+	testCompile project(path: ':briar-tests')
+	testCompile 'org.robolectric:robolectric:3.0'
+	testCompile 'org.mockito:mockito-core:1.10.19'
+
+	androidTestCompile 'org.robolectric:robolectric:3.0'
+	androidTestCompile 'org.mockito:mockito-core:1.10.19'
+	androidTestApt 'com.google.dagger:dagger-compiler:2.0.2'
+	androidTestCompile 'junit:junit:4.12'
 }
 
 dependencyVerification {
@@ -80,8 +93,19 @@ android {
 			assets.srcDirs = ['assets']
 		}
 
-		// Move the tests to tests/java, tests/res, etc...
-		instrumentTest.setRoot('tests')
+		androidTest.setRoot('androidTest')
+		androidTest {
+			java.srcDirs = ['androidTest/java']
+		}
+
+		test.setRoot('test')
+		test {
+			java.srcDirs = ['test/java']
+			testOptions {
+				unitTests.returnDefaultValues = true
+			}
+		}
+
 
 		// Move the build types to build-types/<type>
 		// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
diff --git a/briar-android/proguard-rules.txt b/briar-android/proguard-rules.txt
index 48d785a430ba139f85a88a0a71396a4b5b5671fc..3f11de5e3bc4635ddd3fbc97833267f45188b5b9 100644
--- a/briar-android/proguard-rules.txt
+++ b/briar-android/proguard-rules.txt
@@ -3,6 +3,7 @@
 -dontpreverify
 -dontobfuscate
 -verbose
+-useuniqueclassmembernames
 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
 # For comfortability in case we do obfuscate
 # -renamesourcefileattribute SourceFile
diff --git a/briar-android/res/layout/fragment_dashboard.xml b/briar-android/res/layout/fragment_dashboard.xml
deleted file mode 100644
index 1d73431f59b46c0699d6cef6895bdd8d54bafff1..0000000000000000000000000000000000000000
--- a/briar-android/res/layout/fragment_dashboard.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout
-	xmlns:android="http://schemas.android.com/apk/res/android"
-	android:layout_width="match_parent"
-	android:layout_height="match_parent"
-	android:background="@color/dashboard_background"
-	>
-
-
-</RelativeLayout>
\ No newline at end of file
diff --git a/briar-android/src/org/briarproject/android/ActivityComponent.java b/briar-android/src/org/briarproject/android/ActivityComponent.java
new file mode 100644
index 0000000000000000000000000000000000000000..529bbf7ba2a69379d6e56580d2ef8206467e0493
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/ActivityComponent.java
@@ -0,0 +1,107 @@
+package org.briarproject.android;
+
+import android.app.Activity;
+
+import org.briarproject.android.contact.ConversationActivity;
+import org.briarproject.android.forum.AvailableForumsActivity;
+import org.briarproject.android.forum.ContactSelectorFragment;
+import org.briarproject.android.forum.CreateForumActivity;
+import org.briarproject.android.forum.ForumActivity;
+import org.briarproject.android.forum.ReadForumPostActivity;
+import org.briarproject.android.forum.ShareForumActivity;
+import org.briarproject.android.forum.ShareForumMessageFragment;
+import org.briarproject.android.forum.WriteForumPostActivity;
+import org.briarproject.android.fragment.BaseFragment;
+import org.briarproject.android.identity.CreateIdentityActivity;
+import org.briarproject.android.introduction.IntroductionActivity;
+import org.briarproject.android.introduction.IntroductionMessageFragment;
+import org.briarproject.android.invitation.AddContactActivity;
+import org.briarproject.android.keyagreement.KeyAgreementActivity;
+import org.briarproject.android.panic.PanicPreferencesActivity;
+import org.briarproject.android.panic.PanicResponderActivity;
+
+import javax.inject.Named;
+
+import dagger.Component;
+
+@ActivityScope
+@Component(modules = ActivityModule.class,
+		dependencies = AndroidComponent.class)
+public interface ActivityComponent {
+	Activity activity();
+
+	void inject(SplashScreenActivity activity);
+
+	void inject(SetupActivity activity);
+
+	void inject(NavDrawerActivity activity);
+
+	void inject(PasswordActivity activity);
+
+	void inject(PanicResponderActivity activity);
+
+	void inject(PanicPreferencesActivity activity);
+
+	void inject(AddContactActivity activity);
+
+	void inject(KeyAgreementActivity activity);
+
+	void inject(ConversationActivity activity);
+
+	void inject(CreateIdentityActivity activity);
+
+	void inject(AvailableForumsActivity activity);
+
+	void inject(WriteForumPostActivity activity);
+
+	void inject(CreateForumActivity activity);
+
+	void inject(ShareForumActivity activity);
+
+	void inject(ReadForumPostActivity activity);
+
+	void inject(ForumActivity activity);
+
+	void inject(SettingsActivity activity);
+
+	/*
+	void inject(ContactListFragment fragment);
+
+	void inject(ForumListFragment fragment);
+
+	void inject(ShowQrCodeFragment fragment);
+	*/
+
+	void inject(IntroductionActivity activity);
+
+	/*
+	void inject(ContactChooserFragment fragment);
+
+	void inject(introductionmessagefragment fragment);
+
+	*/
+
+	@Named("ContactListFragment")
+	BaseFragment newContactListFragment();
+
+	@Named("ForumListFragment")
+	BaseFragment newForumListFragment();
+
+	@Named("ChooseIdentityFragment")
+	BaseFragment newChooseIdentityFragment();
+
+	@Named("ShowQrCodeFragment")
+	BaseFragment newShowQrCodeFragment();
+
+	@Named("ContactChooserFragment")
+	BaseFragment newContactChooserFragment();
+
+	@Named("ContactSelectorFragment")
+	ContactSelectorFragment newContactSelectorFragment();
+
+	@Named("ShareForumMessageFragment")
+	ShareForumMessageFragment newShareForumMessageFragment();
+
+	@Named("IntroductionMessageFragment")
+	IntroductionMessageFragment newIntroductionMessageFragment();
+}
diff --git a/briar-android/src/org/briarproject/android/ActivityModule.java b/briar-android/src/org/briarproject/android/ActivityModule.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ed65e9beca59f3dd4a666910c5a44b0c45316c7
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/ActivityModule.java
@@ -0,0 +1,175 @@
+package org.briarproject.android;
+
+import android.app.Activity;
+import android.content.Context;
+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.BriarControllerImpl;
+import org.briarproject.android.controller.ConfigController;
+import org.briarproject.android.controller.ConfigControllerImpl;
+import org.briarproject.android.controller.NavDrawerController;
+import org.briarproject.android.controller.NavDrawerControllerImpl;
+import org.briarproject.android.controller.PasswordController;
+import org.briarproject.android.controller.PasswordControllerImpl;
+import org.briarproject.android.controller.SetupController;
+import org.briarproject.android.controller.SetupControllerImpl;
+import org.briarproject.android.controller.TransportStateListener;
+import org.briarproject.android.forum.ContactSelectorFragment;
+import org.briarproject.android.forum.ForumListFragment;
+import org.briarproject.android.forum.ShareForumMessageFragment;
+import org.briarproject.android.fragment.BaseFragment;
+import org.briarproject.android.introduction.ContactChooserFragment;
+import org.briarproject.android.introduction.IntroductionMessageFragment;
+import org.briarproject.android.keyagreement.ChooseIdentityFragment;
+import org.briarproject.android.keyagreement.ShowQrCodeFragment;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+import static org.briarproject.android.BriarService.BriarServiceConnection;
+
+@Module
+public class ActivityModule {
+
+	private final BaseActivity activity;
+
+	public ActivityModule(BaseActivity activity) {
+		this.activity = activity;
+	}
+
+	@ActivityScope
+	@Provides
+	BaseActivity providesBaseActivity() {
+		return activity;
+	}
+
+	@ActivityScope
+	@Provides
+	Activity providesActivity() {
+		return activity;
+	}
+
+	@ActivityScope
+	@Provides
+	protected SetupController provideSetupController(
+			SetupControllerImpl setupControllerImpl) {
+		return setupControllerImpl;
+	}
+
+	@ActivityScope
+	@Provides
+	protected ConfigController provideConfigController(
+			ConfigControllerImpl configControllerImpl) {
+		return configControllerImpl;
+	}
+
+	@ActivityScope
+	@Provides
+	protected SharedPreferences provideSharedPreferences(Activity activity) {
+		return activity.getSharedPreferences("db", Context.MODE_PRIVATE);
+	}
+
+	@ActivityScope
+	@Provides
+	protected PasswordController providePasswordController(
+			PasswordControllerImpl passwordControllerImp) {
+		return passwordControllerImp;
+	}
+
+	@ActivityScope
+	@Provides
+	protected BriarController provideBriarController(
+			BriarControllerImpl briarControllerImpl) {
+		activity.addLifecycleController(briarControllerImpl);
+		return briarControllerImpl;
+	}
+
+	@ActivityScope
+	@Provides
+	protected NavDrawerController provideNavDrawerController(
+			NavDrawerControllerImpl navDrawerControllerImp) {
+		activity.addLifecycleController(navDrawerControllerImp);
+		if (activity instanceof TransportStateListener) {
+			navDrawerControllerImp
+					.setTransportListener((TransportStateListener) activity);
+		}
+		return navDrawerControllerImp;
+	}
+
+	@ActivityScope
+	@Provides
+	protected BriarServiceConnection provideBriarServiceConnection() {
+		return new BriarServiceConnection();
+	}
+
+	@Provides
+	@Named("ForumListFragment")
+	BaseFragment provideForumListFragment(
+			ForumListFragment forumListFragment) {
+		forumListFragment.setArguments(new Bundle());
+		return forumListFragment;
+	}
+
+	@Provides
+	@Named("ContactListFragment")
+	BaseFragment provideContactListFragment(
+			ContactListFragment contactListFragment) {
+		contactListFragment.setArguments(new Bundle());
+		return contactListFragment;
+	}
+
+	@Provides
+	@Named("ChooseIdentityFragment")
+	BaseFragment provideChooseIdendityFragment() {
+		ChooseIdentityFragment fragment = new ChooseIdentityFragment();
+		fragment.setArguments(new Bundle());
+		return fragment;
+	}
+
+	@Provides
+	@Named("ShowQrCodeFragment")
+	BaseFragment provideShowQrCodeFragment() {
+		ShowQrCodeFragment fragment = new ShowQrCodeFragment();
+		fragment.setArguments(new Bundle());
+		return fragment;
+	}
+
+	@Provides
+	@Named("ContactChooserFragment")
+	BaseFragment provideContactChooserFragment() {
+		ContactChooserFragment fragment = new ContactChooserFragment();
+		fragment.setArguments(new Bundle());
+		return fragment;
+	}
+
+	@Provides
+	@Named("ContactSelectorFragment")
+	ContactSelectorFragment provideContactSelectorFragment() {
+		ContactSelectorFragment fragment = new ContactSelectorFragment();
+		fragment.setArguments(new Bundle());
+		return fragment;
+	}
+
+	@Provides
+	@Named("ShareForumMessageFragment")
+	ShareForumMessageFragment provideShareForumMessageFragment() {
+		ShareForumMessageFragment fragment = new ShareForumMessageFragment();
+		fragment.setArguments(new Bundle());
+		return fragment;
+	}
+
+	@Provides
+	@Named("IntroductionMessageFragment")
+	IntroductionMessageFragment provideIntroductionMessageFragment() {
+		IntroductionMessageFragment fragment =
+				new IntroductionMessageFragment();
+		fragment.setArguments(new Bundle());
+		return fragment;
+	}
+
+}
diff --git a/briar-android/src/org/briarproject/android/ActivityScope.java b/briar-android/src/org/briarproject/android/ActivityScope.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6ceb30ab7d9896edcf523aa2d6d22ed377b2fde
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/ActivityScope.java
@@ -0,0 +1,11 @@
+package org.briarproject.android;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Scope;
+
+@Scope
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ActivityScope {
+}
diff --git a/briar-android/src/org/briarproject/android/AndroidComponent.java b/briar-android/src/org/briarproject/android/AndroidComponent.java
index 8b2ac951ab65f8b7ed6e5565f850a054d06719bf..ba2578addca7d1cd26378440b28add5ba3b20420 100644
--- a/briar-android/src/org/briarproject/android/AndroidComponent.java
+++ b/briar-android/src/org/briarproject/android/AndroidComponent.java
@@ -2,31 +2,41 @@ package org.briarproject.android;
 
 import org.briarproject.CoreEagerSingletons;
 import org.briarproject.CoreModule;
-import org.briarproject.android.contact.ContactListFragment;
-import org.briarproject.android.contact.ConversationActivity;
-import org.briarproject.android.forum.AvailableForumsActivity;
-import org.briarproject.android.forum.ContactSelectorFragment;
-import org.briarproject.android.forum.CreateForumActivity;
-import org.briarproject.android.forum.ForumActivity;
-import org.briarproject.android.forum.ForumListFragment;
-import org.briarproject.android.forum.ReadForumPostActivity;
-import org.briarproject.android.forum.ShareForumActivity;
-import org.briarproject.android.forum.ShareForumMessageFragment;
-import org.briarproject.android.forum.WriteForumPostActivity;
-import org.briarproject.android.identity.CreateIdentityActivity;
-import org.briarproject.android.introduction.ContactChooserFragment;
-import org.briarproject.android.introduction.IntroductionActivity;
-import org.briarproject.android.introduction.IntroductionMessageFragment;
-import org.briarproject.android.invitation.AddContactActivity;
-import org.briarproject.android.keyagreement.ChooseIdentityFragment;
-import org.briarproject.android.keyagreement.KeyAgreementActivity;
-import org.briarproject.android.keyagreement.ShowQrCodeFragment;
-import org.briarproject.android.panic.PanicPreferencesActivity;
-import org.briarproject.android.panic.PanicResponderActivity;
+import org.briarproject.android.api.AndroidExecutor;
+import org.briarproject.android.api.AndroidNotificationManager;
+import org.briarproject.android.api.ReferenceManager;
 import org.briarproject.android.util.BriarReportSender;
+import org.briarproject.api.contact.ContactExchangeTask;
+import org.briarproject.api.contact.ContactManager;
+import org.briarproject.api.crypto.CryptoComponent;
+import org.briarproject.api.crypto.CryptoExecutor;
+import org.briarproject.api.crypto.PasswordStrengthEstimator;
+import org.briarproject.api.db.DatabaseConfig;
+import org.briarproject.api.db.DatabaseExecutor;
+import org.briarproject.api.event.EventBus;
+import org.briarproject.api.forum.ForumManager;
+import org.briarproject.api.forum.ForumPostFactory;
+import org.briarproject.api.forum.ForumSharingManager;
+import org.briarproject.api.identity.AuthorFactory;
+import org.briarproject.api.identity.IdentityManager;
+import org.briarproject.api.introduction.IntroductionManager;
+import org.briarproject.api.invitation.InvitationTaskFactory;
+import org.briarproject.api.keyagreement.KeyAgreementTaskFactory;
+import org.briarproject.api.keyagreement.PayloadEncoder;
+import org.briarproject.api.keyagreement.PayloadParser;
+import org.briarproject.api.lifecycle.IoExecutor;
+import org.briarproject.api.lifecycle.LifecycleManager;
+import org.briarproject.api.messaging.MessagingManager;
+import org.briarproject.api.messaging.PrivateMessageFactory;
+import org.briarproject.api.plugins.ConnectionRegistry;
+import org.briarproject.api.plugins.PluginManager;
+import org.briarproject.api.properties.TransportPropertyManager;
+import org.briarproject.api.settings.SettingsManager;
 import org.briarproject.plugins.AndroidPluginsModule;
 import org.briarproject.system.AndroidSystemModule;
 
+import java.util.concurrent.Executor;
+
 import javax.inject.Singleton;
 
 import dagger.Component;
@@ -39,62 +49,71 @@ import dagger.Component;
 		AndroidSystemModule.class
 })
 public interface AndroidComponent extends CoreEagerSingletons {
+	// Exposed objects
+	@CryptoExecutor
+	Executor cryptoExecutor();
 
-	void inject(DevReportActivity devReportActivity);
+	PasswordStrengthEstimator passwordStrengthIndicator();
 
-	void inject(SplashScreenActivity activity);
+	CryptoComponent cryptoComponent();
 
-	void inject(SetupActivity activity);
+	DatabaseConfig databaseConfig();
 
-	void inject(NavDrawerActivity activity);
+	AuthorFactory authFactory();
 
-	void inject(PasswordActivity activity);
+	ReferenceManager referenceMangager();
 
-	void inject(BriarService activity);
+	@DatabaseExecutor
+	Executor databaseExecutor();
+
+	LifecycleManager lifecycleManager();
 
-	void inject(PanicResponderActivity activity);
+	IdentityManager identityManager();
 
-	void inject(PanicPreferencesActivity activity);
+	PluginManager pluginManager();
 
-	void inject(AddContactActivity activity);
+	EventBus eventBus();
 
-	void inject(KeyAgreementActivity activity);
+	InvitationTaskFactory invitationTaskFactory();
 
-	void inject(ConversationActivity activity);
+	AndroidNotificationManager androidNotificationManager();
 
-	void inject(CreateIdentityActivity activity);
+	ConnectionRegistry connectionRegistry();
 
-	void inject(AvailableForumsActivity activity);
+	ContactManager contactManager();
 
-	void inject(WriteForumPostActivity activity);
+	MessagingManager messagingManager();
 
-	void inject(CreateForumActivity activity);
+	PrivateMessageFactory privateMessageFactory();
 
-	void inject(ShareForumActivity activity);
+	TransportPropertyManager transportPropertyManager();
 
-	void inject(ContactSelectorFragment fragment);
+	ForumManager forumManager();
 
-	void inject(ShareForumMessageFragment fragment);
+	ForumSharingManager forumSharingManager();
 
-	void inject(ReadForumPostActivity activity);
+	ForumPostFactory forumPostFactory();
 
-	void inject(ForumActivity activity);
+	SettingsManager settingsManager();
 
-	void inject(SettingsActivity activity);
+	ContactExchangeTask contactExchangeTask();
 
-	void inject(ContactListFragment fragment);
+	KeyAgreementTaskFactory keyAgreementTaskFactory();
 
-	void inject(ForumListFragment fragment);
+	PayloadEncoder payloadEncoder();
 
-	void inject(ChooseIdentityFragment fragment);
+	PayloadParser payloadParser();
 
-	void inject(ShowQrCodeFragment fragment);
+	IntroductionManager introductionManager();
 
-	void inject(IntroductionActivity activity);
+	AndroidExecutor androidExecutor();
 
-	void inject(ContactChooserFragment fragment);
+	@IoExecutor
+	Executor ioExecutor();
 
-	void inject(IntroductionMessageFragment fragment);
+	void inject(DevReportActivity devReportActivity);
+
+	void inject(BriarService activity);
 
 	// Eager singleton load
 	void inject(AppModule.EagerSingletons init);
diff --git a/briar-android/src/org/briarproject/android/BaseActivity.java b/briar-android/src/org/briarproject/android/BaseActivity.java
index 1a93a006ec6b200e2522e8431c4168eefc1efdbc..fa2e68d6b8e57d60d3f7d693a5b14fb0e7a72275 100644
--- a/briar-android/src/org/briarproject/android/BaseActivity.java
+++ b/briar-android/src/org/briarproject/android/BaseActivity.java
@@ -1,21 +1,31 @@
 package org.briarproject.android;
 
-import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.support.v7.app.AppCompatActivity;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 
+import org.briarproject.android.controller.ActivityLifecycleController;
+
+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 {
 
-	public final static String PREFS_NAME = "db";
-	public final static String PREF_DB_KEY = "key";
-	public final static String PREF_SEEN_WELCOME_MESSAGE = "welcome_message";
+	protected ActivityComponent activityComponent;
+
+	private List<ActivityLifecycleController> lifecycleControllers =
+			new ArrayList<ActivityLifecycleController>();
+
+	public void addLifecycleController(
+			ActivityLifecycleController lifecycleController) {
+		this.lifecycleControllers.add(lifecycleController);
+	}
 
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
@@ -23,32 +33,52 @@ public abstract class BaseActivity extends AppCompatActivity {
 
 		if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
 
-		BriarApplication application = (BriarApplication) getApplication();
-		injectActivity(application.getApplicationComponent());
-	}
+		AndroidComponent applicationComponent =
+				((BriarApplication) getApplication()).getApplicationComponent();
+
+		activityComponent = DaggerActivityComponent.builder()
+				.androidComponent(applicationComponent)
+				.activityModule(getActivityModule())
+				.build();
 
-	public abstract void injectActivity(AndroidComponent component);
+		injectActivity(activityComponent);
 
-	private SharedPreferences getSharedPrefs() {
-		return getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
+		for (ActivityLifecycleController alc : lifecycleControllers) {
+			alc.onActivityCreate();
+		}
 	}
 
-	protected String getEncryptedDatabaseKey() {
-		return getSharedPrefs().getString(PREF_DB_KEY, null);
+	// This exists to make test overrides easier
+	protected ActivityModule getActivityModule() {
+		return new ActivityModule(this);
 	}
 
-	protected void storeEncryptedDatabaseKey(final String hex) {
-		SharedPreferences.Editor editor = getSharedPrefs().edit();
-		editor.putString(PREF_DB_KEY, hex);
-		editor.apply();
+	@Override
+	protected void onResume() {
+		super.onResume();
+		for (ActivityLifecycleController alc : lifecycleControllers) {
+			alc.onActivityResume();
+		}
 	}
 
-	protected void clearSharedPrefs() {
-		SharedPreferences.Editor editor = getSharedPrefs().edit();
-		editor.clear();
-		editor.apply();
+	@Override
+	protected void onPause() {
+		super.onPause();
+		for (ActivityLifecycleController alc : lifecycleControllers) {
+			alc.onActivityPause();
+		}
 	}
 
+	@Override
+	protected void onDestroy() {
+		super.onDestroy();
+		for (ActivityLifecycleController alc : lifecycleControllers) {
+			alc.onActivityDestroy();
+		}
+	}
+
+	public abstract void injectActivity(ActivityComponent component);
+
 	protected void showSoftKeyboard(View view) {
 		Object o = getSystemService(INPUT_METHOD_SERVICE);
 		((InputMethodManager) o).showSoftInput(view, SHOW_IMPLICIT);
@@ -59,4 +89,5 @@ public abstract class BaseActivity extends AppCompatActivity {
 		Object o = getSystemService(INPUT_METHOD_SERVICE);
 		((InputMethodManager) o).hideSoftInputFromWindow(token, 0);
 	}
+
 }
diff --git a/briar-android/src/org/briarproject/android/BriarActivity.java b/briar-android/src/org/briarproject/android/BriarActivity.java
index 8043b1a14038cb473963917a06bfe2e427b97edc..0da52cf2be6bfd4689d2d42afbbf5f9acdefea63 100644
--- a/briar-android/src/org/briarproject/android/BriarActivity.java
+++ b/briar-android/src/org/briarproject/android/BriarActivity.java
@@ -3,17 +3,11 @@ package org.briarproject.android;
 import android.annotation.SuppressLint;
 import android.content.Intent;
 import android.os.Build;
-import android.os.Bundle;
-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.handler.UiResultHandler;
 import org.briarproject.android.panic.ExitActivity;
-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;
@@ -37,33 +31,14 @@ 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;
-
-	private boolean bound = false;
-
-	// Fields that are accessed from background threads must be volatile
 	@Inject
-	@DatabaseExecutor
-	protected volatile Executor dbExecutor;
-	@Inject
-	protected volatile LifecycleManager lifecycleManager;
-
-	@Override
-	public void onCreate(Bundle state) {
-		super.onCreate(state);
-
-		if (databaseConfig.getEncryptionKey() != null) startAndBindService();
-	}
+	protected BriarController briarController;
 
 	@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,51 +46,22 @@ public abstract class BriarActivity extends BaseActivity {
 	@Override
 	public void onResume() {
 		super.onResume();
-		if (databaseConfig.getEncryptionKey() == null && !isFinishing()) {
+		if (!briarController.hasEncryptionKey() && !isFinishing()) {
 			Intent i = new Intent(this, PasswordActivity.class);
 			i.setFlags(FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_SINGLE_TOP);
 			startActivityForResult(i, REQUEST_PASSWORD);
 		}
 	}
 
-	@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);
-	}
-
 	protected void signOut(final boolean removeFromRecentApps) {
-		// Use a new thread to avoid deadlock with executor tasks
-		new Thread() {
+		briarController.signOut(new UiResultHandler<Void>(this) {
+
 			@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 onResultUi(Void result) {
 				if (removeFromRecentApps) startExitActivity();
 				else finishAndExit();
 			}
-		}.start();
+		});
 	}
 
 	protected void signOut() {
@@ -123,46 +69,29 @@ 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();
-				}
-			}
-		});
+	@Deprecated
+	public void runOnDbThread(Runnable task) {
+		briarController.runOnDbThread(task);
 	}
 
+	@Deprecated
 	protected void finishOnUiThread() {
 		runOnUiThread(new Runnable() {
 			public void run() {
diff --git a/briar-android/src/org/briarproject/android/BriarApplication.java b/briar-android/src/org/briarproject/android/BriarApplication.java
index eec480309deb5f4ae863345868662f0a6d4d670c..cd28990adcaefb0cd28629747175e1b596629f13 100644
--- a/briar-android/src/org/briarproject/android/BriarApplication.java
+++ b/briar-android/src/org/briarproject/android/BriarApplication.java
@@ -1,56 +1,10 @@
 package org.briarproject.android;
 
-import android.app.Application;
-import android.content.Context;
+/**
+ * This exists so that the Application object will not necessarily be cast
+ * directly to the Briar application object.
+ */
+public interface BriarApplication {
 
-import org.acra.ACRA;
-import org.acra.ReportingInteractionMode;
-import org.acra.annotation.ReportsCrashes;
-import org.briarproject.CoreModule;
-import org.briarproject.R;
-import org.briarproject.android.util.BriarReportPrimer;
-import org.briarproject.android.util.BriarReportSenderFactory;
-
-import java.util.logging.Logger;
-
-@ReportsCrashes(
-		reportPrimerClass = BriarReportPrimer.class,
-		logcatArguments = {"-d", "-v", "time", "*:I"},
-		reportSenderFactoryClasses = {BriarReportSenderFactory.class},
-		mode = ReportingInteractionMode.DIALOG,
-		reportDialogClass = DevReportActivity.class,
-		resDialogOkToast = R.string.dev_report_saved,
-		deleteOldUnsentReportsOnApplicationStart = false
-)
-public class BriarApplication extends Application {
-
-	private static final Logger LOG =
-			Logger.getLogger(BriarApplication.class.getName());
-
-	private AndroidComponent applicationComponent;
-
-	@Override
-	protected void attachBaseContext(Context base) {
-		super.attachBaseContext(base);
-		ACRA.init(this);
-	}
-
-	@Override
-	public void onCreate() {
-		super.onCreate();
-		LOG.info("Created");
-
-		applicationComponent = DaggerAndroidComponent.builder()
-				.appModule(new AppModule(this))
-				.build();
-
-		// We need to load the eager singletons directly after making the
-		// dependency graphs
-		CoreModule.initEagerSingletons(applicationComponent);
-		AndroidEagerSingletons.initEagerSingletons(applicationComponent);
-	}
-
-	public AndroidComponent getApplicationComponent() {
-		return applicationComponent;
-	}
+	AndroidComponent getApplicationComponent();
 }
diff --git a/briar-android/src/org/briarproject/android/BriarApplicationImpl.java b/briar-android/src/org/briarproject/android/BriarApplicationImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..5abe5dff2d542cec09ffd8be44e930ea24e6d800
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/BriarApplicationImpl.java
@@ -0,0 +1,56 @@
+package org.briarproject.android;
+
+import android.app.Application;
+import android.content.Context;
+
+import org.acra.ACRA;
+import org.acra.ReportingInteractionMode;
+import org.acra.annotation.ReportsCrashes;
+import org.briarproject.CoreModule;
+import org.briarproject.R;
+import org.briarproject.android.util.BriarReportPrimer;
+import org.briarproject.android.util.BriarReportSenderFactory;
+
+import java.util.logging.Logger;
+
+@ReportsCrashes(
+		reportPrimerClass = BriarReportPrimer.class,
+		logcatArguments = {"-d", "-v", "time", "*:I"},
+		reportSenderFactoryClasses = {BriarReportSenderFactory.class},
+		mode = ReportingInteractionMode.DIALOG,
+		reportDialogClass = DevReportActivity.class,
+		resDialogOkToast = R.string.dev_report_saved,
+		deleteOldUnsentReportsOnApplicationStart = false
+)
+public class BriarApplicationImpl extends Application implements BriarApplication {
+
+	private static final Logger LOG =
+			Logger.getLogger(BriarApplicationImpl.class.getName());
+
+	private AndroidComponent applicationComponent;
+
+	@Override
+	protected void attachBaseContext(Context base) {
+		super.attachBaseContext(base);
+		ACRA.init(this);
+	}
+
+	@Override
+	public void onCreate() {
+		super.onCreate();
+		LOG.info("Created");
+
+		applicationComponent = DaggerAndroidComponent.builder()
+				.appModule(new AppModule(this))
+				.build();
+
+		// We need to load the eager singletons directly after making the
+		// dependency graphs
+		CoreModule.initEagerSingletons(applicationComponent);
+		AndroidEagerSingletons.initEagerSingletons(applicationComponent);
+	}
+
+	public AndroidComponent getApplicationComponent() {
+		return applicationComponent;
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/BriarFragmentActivity.java b/briar-android/src/org/briarproject/android/BriarFragmentActivity.java
index 766a11e33044711faa87e978d22682d9ea4b2fe8..00fe0f39acd18b60e4339ef8deaca47ebb305097 100644
--- a/briar-android/src/org/briarproject/android/BriarFragmentActivity.java
+++ b/briar-android/src/org/briarproject/android/BriarFragmentActivity.java
@@ -10,7 +10,6 @@ import org.briarproject.R;
 import org.briarproject.android.contact.ContactListFragment;
 import org.briarproject.android.forum.ForumListFragment;
 import org.briarproject.android.fragment.BaseFragment;
-import org.briarproject.android.fragment.DashboardFragment;
 
 /**
  * This class should be extended by classes that wish to utilise fragments in
@@ -23,9 +22,7 @@ public abstract class BriarFragmentActivity extends BriarActivity {
 		if (actionBar == null)
 			return;
 
-		if (fragmentTag.equals(DashboardFragment.TAG)) {
-			actionBar.setTitle(R.string.dashboard_toolbar_header);
-		} else if (fragmentTag.equals(ContactListFragment.TAG)) {
+		if (fragmentTag.equals(ContactListFragment.TAG)) {
 			actionBar.setTitle(R.string.contacts_toolbar_header);
 		} else if (fragmentTag.equals(ForumListFragment.TAG)) {
 			actionBar.setTitle(R.string.forums_toolbar_header);
@@ -52,7 +49,7 @@ public abstract class BriarFragmentActivity extends BriarActivity {
 			exiting. This models the typical Google navigation behaviour such
 			as in Gmail/Inbox.
 			 */
-			startFragment(ContactListFragment.newInstance());
+			startFragment(activityComponent.newContactListFragment());
 
 		} else {
 			super.onBackPressed();
diff --git a/briar-android/src/org/briarproject/android/DevReportActivity.java b/briar-android/src/org/briarproject/android/DevReportActivity.java
index 2ea4e07e370b558cef1e433bb3a2febb0fb1295a..8f94b5a07624c4e9cc6f4e42d9ad8e7e01ebeb0c 100644
--- a/briar-android/src/org/briarproject/android/DevReportActivity.java
+++ b/briar-android/src/org/briarproject/android/DevReportActivity.java
@@ -89,6 +89,7 @@ public class DevReportActivity extends BaseCrashReportDialog
 		((BriarApplication) getApplication()).getApplicationComponent()
 				.inject(this);
 
+
 		sharedPreferencesFactory =
 				new SharedPreferencesFactory(getApplicationContext(),
 						getConfig());
diff --git a/briar-android/src/org/briarproject/android/NavDrawerActivity.java b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
index 367bb12ba16daf71f903ce4e1218e610850dad15..4d18cd6ec588ebcb0834e503a72923ac3425fb9b 100644
--- a/briar-android/src/org/briarproject/android/NavDrawerActivity.java
+++ b/briar-android/src/org/briarproject/android/NavDrawerActivity.java
@@ -1,5 +1,6 @@
 package org.briarproject.android;
 
+import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
@@ -13,28 +14,18 @@ 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.TransportStateListener;
+import org.briarproject.android.controller.handler.UiResultHandler;
 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;
@@ -42,11 +33,10 @@ 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";
 
 	public static final String INTENT_CONTACTS = "intent_contacts";
 	public static final String INTENT_FORUMS = "intent_forums";
@@ -57,20 +47,10 @@ 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;
+	protected NavDrawerController controller;
 
 	private Toolbar toolbar;
 	private DrawerLayout drawerLayout;
-	private Button contactButton;
-	private Button forumsButton;
-	private Button settingsButton;
 	private GridView transportsView;
 	private TextView progressTitle;
 	private ViewGroup progressViewGroup;
@@ -85,14 +65,14 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 			checkAuthorHandle(intent);
 			clearBackStack();
 			if (intent.getBooleanExtra(INTENT_FORUMS, false))
-				startFragment(ForumListFragment.newInstance());
+				startFragment(activityComponent.newForumListFragment());
 			else if (intent.getBooleanExtra(INTENT_CONTACTS, false))
-				startFragment(ContactListFragment.newInstance());
+				startFragment(activityComponent.newContactListFragment());
 		}
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
@@ -106,14 +86,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);
-		contactButton = (Button)findViewById(R.id.nav_btn_contacts);
-		forumsButton = (Button)findViewById(R.id.nav_btn_forums);
-		settingsButton = (Button)findViewById(R.id.nav_btn_settings);
-		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);
@@ -133,7 +110,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 			}
 		};
 		drawerLayout.setDrawerListener(drawerToggle);
-		if (state == null) startFragment(ContactListFragment.newInstance());
+		if (state == null) startFragment(activityComponent.newContactListFragment());
 		checkAuthorHandle(getIntent());
 
 		initializeTransports(getLayoutInflater());
@@ -143,8 +120,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 	}
 
 	private void welcomeMessageCheck() {
-		SharedPreferences prefs = getSharedPreferences(PREFS_NAME,
-				MODE_PRIVATE);
+		SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
 		if (!prefs.getBoolean(PREF_SEEN_WELCOME_MESSAGE, false)) {
 			showMessageDialog(R.string.dialog_title_welcome,
 					R.string.dialog_welcome_message);
@@ -155,22 +131,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);
@@ -189,27 +157,13 @@ 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 UiResultHandler<Void>(this) {
+					@Override
+					public void onResultUi(Void result) {
+						hideLoadingScreen();
+					}
+				});
 	}
 
 	public void onNavigationClick(View view) {
@@ -217,10 +171,10 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 		clearBackStack();
 		switch (view.getId()) {
 			case R.id.nav_btn_contacts:
-				startFragment(ContactListFragment.newInstance());
+				startFragment(activityComponent.newContactListFragment());
 				break;
 			case R.id.nav_btn_forums:
-				startFragment(ForumListFragment.newInstance());
+				startFragment(activityComponent.newForumListFragment());
 				break;
 			case R.id.nav_btn_settings:
 				startActivity(new Intent(this, SettingsActivity.class));
@@ -243,7 +197,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
 	}
 
 	@Override
-	protected void onPostCreate(Bundle savedInstanceState) {
+	public void onPostCreate(Bundle savedInstanceState) {
 		super.onPostCreate(savedInstanceState);
 		drawerToggle.syncState();
 	}
@@ -285,24 +239,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.isTransportRunning(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.isTransportRunning(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.isTransportRunning(lan.id);
 		lan.iconId = R.drawable.transport_lan;
 		lan.textId = R.string.transport_lan;
 		transports.add(lan);
@@ -369,27 +320,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.isTransportRunning(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 33f14f206b1b2c7ef29c640d061b3d1595dcd916..346b2f2cd96f5e69b1db0de6038d744c27b63913 100644
--- a/briar-android/src/org/briarproject/android/PasswordActivity.java
+++ b/briar-android/src/org/briarproject/android/PasswordActivity.java
@@ -3,6 +3,7 @@ package org.briarproject.android;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 import android.support.design.widget.TextInputLayout;
 import android.support.v7.app.AlertDialog;
 import android.text.Editable;
@@ -16,14 +17,9 @@ import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
 import org.briarproject.R;
+import org.briarproject.android.controller.PasswordController;
+import org.briarproject.android.controller.handler.UiResultHandler;
 import org.briarproject.android.util.AndroidUtils;
-import org.briarproject.api.crypto.CryptoComponent;
-import org.briarproject.api.crypto.CryptoExecutor;
-import org.briarproject.api.crypto.SecretKey;
-import org.briarproject.api.db.DatabaseConfig;
-import org.briarproject.util.StringUtils;
-
-import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -34,28 +30,22 @@ import static android.view.View.VISIBLE;
 
 public class PasswordActivity extends BaseActivity {
 
-	@Inject @CryptoExecutor protected Executor cryptoExecutor;
 	private Button signInButton;
 	private ProgressBar progress;
 	private TextInputLayout input;
 	private EditText password;
 
-	private byte[] encrypted;
-
-	// Fields that are accessed from background threads must be volatile
-	@Inject protected volatile CryptoComponent crypto;
-	@Inject protected volatile DatabaseConfig databaseConfig;
+	@Inject
+	PasswordController passwordController;
 
 	@Override
 	public void onCreate(Bundle state) {
 		super.onCreate(state);
 
-		String hex = getEncryptedDatabaseKey();
-		if (hex == null || !databaseConfig.databaseExists()) {
+		if (!passwordController.initialized()) {
 			clearSharedPrefsAndDeleteEverything();
 			return;
 		}
-		encrypted = StringUtils.fromHexString(hex);
 
 		setContentView(R.layout.activity_password);
 		signInButton = (Button) findViewById(R.id.btn_sign_in);
@@ -66,8 +56,7 @@ public class PasswordActivity extends BaseActivity {
 			@Override
 			public boolean onEditorAction(TextView v, int actionId,
 					KeyEvent event) {
-				hideSoftKeyboard(password);
-				validatePassword(encrypted, password.getText());
+				validatePassword();
 				return true;
 			}
 		});
@@ -90,7 +79,7 @@ public class PasswordActivity extends BaseActivity {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
@@ -103,7 +92,7 @@ public class PasswordActivity extends BaseActivity {
 	}
 
 	private void clearSharedPrefsAndDeleteEverything() {
-		clearSharedPrefs();
+		passwordController.clearPrefs();
 		AndroidUtils.deleteAppData(this);
 		setResult(RESULT_CANCELED);
 		startActivity(new Intent(this, SetupActivity.class));
@@ -111,7 +100,7 @@ public class PasswordActivity extends BaseActivity {
 	}
 
 	public void onSignInClick(View v) {
-		validatePassword(encrypted, password.getText());
+		validatePassword();
 	}
 
 	public void onForgottenPasswordClick(View v) {
@@ -132,47 +121,33 @@ public class PasswordActivity extends BaseActivity {
 		dialog.show();
 	}
 
-	private void validatePassword(final byte[] encrypted, Editable e) {
+	private void validatePassword() {
 		hideSoftKeyboard(password);
-		// Replace the button with a progress bar
 		signInButton.setVisibility(INVISIBLE);
 		progress.setVisibility(VISIBLE);
-		// Decrypt the database key in a background thread
-		final String password = e.toString();
-		cryptoExecutor.execute(new Runnable() {
-			public void run() {
-				byte[] key = crypto.decryptWithPassword(encrypted, password);
-				if (key == null) {
-					tryAgain();
-				} else {
-					databaseConfig.setEncryptionKey(new SecretKey(key));
-					setResultAndFinish();
-				}
-			}
-		});
+		passwordController.validatePassword(password.getText().toString(),
+				new UiResultHandler<Boolean>(this) {
+					@Override
+					public void onResultUi(@NonNull Boolean result) {
+						if (result) {
+							setResult(RESULT_OK);
+							finish();
+						} else {
+							tryAgain();
+						}
+					}
+				});
 	}
 
 	private void tryAgain() {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				AndroidUtils.setError(input, getString(R.string.try_again),
-						true);
-				signInButton.setVisibility(VISIBLE);
-				progress.setVisibility(INVISIBLE);
-				password.setText("");
-
-				// show the keyboard again
-				showSoftKeyboard(password);
-			}
-		});
+		AndroidUtils.setError(input, getString(R.string.try_again),
+				true);
+		signInButton.setVisibility(VISIBLE);
+		progress.setVisibility(INVISIBLE);
+		password.setText("");
+
+		// show the keyboard again
+		showSoftKeyboard(password);
 	}
 
-	private void setResultAndFinish() {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				setResult(RESULT_OK);
-				finish();
-			}
-		});
-	}
 }
diff --git a/briar-android/src/org/briarproject/android/SettingsActivity.java b/briar-android/src/org/briarproject/android/SettingsActivity.java
index e270578a74065285f7ee43ee4f7dabc0ca8cffa2..bb783a06517004ff316d1d36763daafb61c8a0be 100644
--- a/briar-android/src/org/briarproject/android/SettingsActivity.java
+++ b/briar-android/src/org/briarproject/android/SettingsActivity.java
@@ -34,7 +34,7 @@ public class SettingsActivity extends BriarActivity {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/SetupActivity.java b/briar-android/src/org/briarproject/android/SetupActivity.java
index 6caf20e5acbaf686aed94603143eb980750689df..13bb49f4b2410e1e222bfb285cbe79e6e6d03fef 100644
--- a/briar-android/src/org/briarproject/android/SetupActivity.java
+++ b/briar-android/src/org/briarproject/android/SetupActivity.java
@@ -2,6 +2,7 @@ package org.briarproject.android;
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 import android.support.design.widget.TextInputLayout;
 import android.text.Editable;
 import android.text.TextWatcher;
@@ -15,29 +16,18 @@ import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
 
 import org.briarproject.R;
+import org.briarproject.android.controller.SetupController;
+import org.briarproject.android.controller.handler.UiResultHandler;
 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.identity.AuthorFactory;
-import org.briarproject.api.identity.LocalAuthor;
 import org.briarproject.util.StringUtils;
 
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-
 import javax.inject.Inject;
 
 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;
@@ -45,17 +35,8 @@ import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENG
 public class SetupActivity extends BaseActivity implements OnClickListener,
 		OnEditorActionListener {
 
-	private static final Logger LOG =
-			Logger.getLogger(SetupActivity.class.getName());
-
-	@Inject @CryptoExecutor protected Executor cryptoExecutor;
-	@Inject protected PasswordStrengthEstimator strengthEstimator;
-
-	// Fields that are accessed from background threads must be volatile
-	@Inject protected volatile CryptoComponent crypto;
-	@Inject protected volatile DatabaseConfig databaseConfig;
-	@Inject protected volatile AuthorFactory authorFactory;
-	@Inject protected volatile ReferenceManager referenceManager;
+	@Inject
+	protected SetupController setupController;
 
 	TextInputLayout nicknameEntryWrapper;
 	TextInputLayout passwordEntryWrapper;
@@ -72,15 +53,18 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
 		super.onCreate(state);
 		setContentView(R.layout.activity_setup);
 
-		nicknameEntryWrapper = (TextInputLayout)findViewById(R.id.nickname_entry_wrapper);
-		passwordEntryWrapper = (TextInputLayout)findViewById(R.id.password_entry_wrapper);
-		passwordConfirmationWrapper = (TextInputLayout)findViewById(R.id.password_confirm_wrapper);
-		nicknameEntry = (EditText)findViewById(R.id.nickname_entry);
-		passwordEntry = (EditText)findViewById(R.id.password_entry);
-		passwordConfirmation = (EditText)findViewById(R.id.password_confirm);
-		strengthMeter = (StrengthMeter)findViewById(R.id.strength_meter);
-		createAccountButton = (Button)findViewById(R.id.create_account);
-		progress = (ProgressBar)findViewById(R.id.progress_wheel);
+		nicknameEntryWrapper =
+				(TextInputLayout) findViewById(R.id.nickname_entry_wrapper);
+		passwordEntryWrapper =
+				(TextInputLayout) findViewById(R.id.password_entry_wrapper);
+		passwordConfirmationWrapper =
+				(TextInputLayout) findViewById(R.id.password_confirm_wrapper);
+		nicknameEntry = (EditText) findViewById(R.id.nickname_entry);
+		passwordEntry = (EditText) findViewById(R.id.password_entry);
+		passwordConfirmation = (EditText) findViewById(R.id.password_confirm);
+		strengthMeter = (StrengthMeter) findViewById(R.id.strength_meter);
+		createAccountButton = (Button) findViewById(R.id.create_account);
+		progress = (ProgressBar) findViewById(R.id.progress_wheel);
 
 		if (PREVENT_SCREENSHOTS) getWindow().addFlags(FLAG_SECURE);
 
@@ -109,7 +93,7 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
@@ -123,7 +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 = setupController.estimatePasswordStrength(firstPassword);
 		strengthMeter.setStrength(strength);
 		AndroidUtils.setError(nicknameEntryWrapper,
 				getString(R.string.name_too_long),
@@ -141,6 +125,7 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
 
 	public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
 		hideSoftKeyboard(v);
+
 		return true;
 	}
 
@@ -150,52 +135,21 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
 		progress.setVisibility(VISIBLE);
 		final String nickname = nicknameEntry.getText().toString();
 		final String password = passwordEntry.getText().toString();
-		// Store the DB key and create the identity in a background thread
-		cryptoExecutor.execute(new Runnable() {
-			public void run() {
-				SecretKey key = crypto.generateSecretKey();
-				databaseConfig.setEncryptionKey(key);
-				String hex = encryptDatabaseKey(key, password);
-				storeEncryptedDatabaseKey(hex);
-				LocalAuthor localAuthor = createLocalAuthor(nickname);
-				showDashboard(referenceManager.putReference(localAuthor,
-						LocalAuthor.class));
-			}
-		});
+		setupController.createIdentity(nickname, password,
+				new UiResultHandler<Long>(this) {
+					@Override
+					public void onResultUi(@NonNull Long result) {
+						showMain(result);
+					}
+				});
 	}
 
-	private String encryptDatabaseKey(SecretKey key, String password) {
-		long now = System.currentTimeMillis();
-		byte[] encrypted = crypto.encryptWithPassword(key.getBytes(), password);
-		long duration = System.currentTimeMillis() - now;
-		if (LOG.isLoggable(INFO))
-			LOG.info("Key derivation took " + duration + " ms");
-		return StringUtils.toHexString(encrypted);
-	}
-
-	private LocalAuthor createLocalAuthor(String nickname) {
-		long now = System.currentTimeMillis();
-		KeyPair keyPair = crypto.generateSignatureKeyPair();
-		byte[] publicKey = keyPair.getPublic().getEncoded();
-		byte[] privateKey = keyPair.getPrivate().getEncoded();
-		LocalAuthor localAuthor = authorFactory.createLocalAuthor(nickname,
-				publicKey, privateKey);
-		long duration = System.currentTimeMillis() - now;
-		if (LOG.isLoggable(INFO))
-			LOG.info("Identity creation took " + duration + " ms");
-		return localAuthor;
-	}
-
-	private void showDashboard(final long handle) {
-		runOnUiThread(new Runnable() {
-			public void run() {
-				Intent i = new Intent(SetupActivity.this,
-						NavDrawerActivity.class);
-				i.putExtra(BriarActivity.KEY_LOCAL_AUTHOR_HANDLE, handle);
-				i.setFlags(FLAG_ACTIVITY_NEW_TASK);
-				startActivity(i);
-				finish();
-			}
-		});
+	private void showMain(final long handle) {
+		Intent i = new Intent(SetupActivity.this,
+				NavDrawerActivity.class);
+		i.putExtra(BriarActivity.KEY_LOCAL_AUTHOR_HANDLE, handle);
+		i.setFlags(FLAG_ACTIVITY_NEW_TASK);
+		startActivity(i);
+		finish();
 	}
 }
diff --git a/briar-android/src/org/briarproject/android/SplashScreenActivity.java b/briar-android/src/org/briarproject/android/SplashScreenActivity.java
index 0ba0d47b9479aa1b8e59432ce4f7993cf199c0f4..e4ff0b9418a3397ab1e893dc267f05a1616a2b4e 100644
--- a/briar-android/src/org/briarproject/android/SplashScreenActivity.java
+++ b/briar-android/src/org/briarproject/android/SplashScreenActivity.java
@@ -10,8 +10,8 @@ import android.support.v7.preference.PreferenceManager;
 
 import org.briarproject.R;
 import org.briarproject.android.api.AndroidExecutor;
+import org.briarproject.android.controller.ConfigController;
 import org.briarproject.android.util.AndroidUtils;
-import org.briarproject.api.db.DatabaseConfig;
 
 import java.util.logging.Logger;
 
@@ -29,7 +29,7 @@ public class SplashScreenActivity extends BaseActivity {
 	private static final long EXPIRY_DATE = 1464735600 * 1000L;
 
 	@Inject
-	protected DatabaseConfig dbConfig;
+	ConfigController configController;
 	@Inject
 	protected AndroidExecutor androidExecutor;
 
@@ -56,7 +56,7 @@ public class SplashScreenActivity extends BaseActivity {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
@@ -65,11 +65,11 @@ public class SplashScreenActivity extends BaseActivity {
 			LOG.info("Expired");
 			startActivity(new Intent(this, ExpiredActivity.class));
 		} else {
-			String hex = getEncryptedDatabaseKey();
-			if (hex != null && dbConfig.databaseExists()) {
+			if (configController.initialized()) {
 				startActivity(new Intent(this, NavDrawerActivity.class));
 			} else {
-				clearSharedPrefs();
+				configController.clearPrefs();
+				// TODO replace this static call with a controller method
 				AndroidUtils.deleteAppData(this);
 				startActivity(new Intent(this, SetupActivity.class));
 			}
diff --git a/briar-android/src/org/briarproject/android/StartupFailureActivity.java b/briar-android/src/org/briarproject/android/StartupFailureActivity.java
index 5180c33c27fe72a5b9fe4b1009f8597bfe7560bf..b258369391ff701b735b130d1ee901c46d22ccb7 100644
--- a/briar-android/src/org/briarproject/android/StartupFailureActivity.java
+++ b/briar-android/src/org/briarproject/android/StartupFailureActivity.java
@@ -20,7 +20,7 @@ public class StartupFailureActivity extends BaseActivity {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 
 	}
 
diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
index 82137d92ad531ebbcb49cca43c635d7d39abb961..5e7e017cd6139f37769bfc4e0bee392947aa7be4 100644
--- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
+++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java
@@ -12,8 +12,7 @@ import android.view.View;
 import android.view.ViewGroup;
 
 import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
-import org.briarproject.android.fragment.BaseEventFragment;
+import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.android.keyagreement.KeyAgreementActivity;
 import org.briarproject.android.util.BriarRecyclerView;
 import org.briarproject.api.contact.Contact;
@@ -28,6 +27,7 @@ import org.briarproject.api.event.ContactRemovedEvent;
 import org.briarproject.api.event.ContactStatusChangedEvent;
 import org.briarproject.api.event.Event;
 import org.briarproject.api.event.EventBus;
+import org.briarproject.api.event.EventListener;
 import org.briarproject.api.event.MessageValidatedEvent;
 import org.briarproject.api.forum.ForumInvitationMessage;
 import org.briarproject.api.forum.ForumSharingManager;
@@ -52,22 +52,13 @@ import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.WARNING;
 import static org.briarproject.android.BriarActivity.GROUP_ID;
 
-public class ContactListFragment extends BaseEventFragment {
+public class ContactListFragment extends BaseFragment implements EventListener {
 
 	private static final Logger LOG =
 			Logger.getLogger(ContactListFragment.class.getName());
 
 	public final static String TAG = "ContactListFragment";
 
-	public static ContactListFragment newInstance() {
-
-		Bundle args = new Bundle();
-
-		ContactListFragment fragment = new ContactListFragment();
-		fragment.setArguments(args);
-		return fragment;
-	}
-
 	@Override
 	public String getUniqueTag() {
 		return TAG;
@@ -92,9 +83,10 @@ public class ContactListFragment extends BaseEventFragment {
 	@Inject
 	protected volatile EventBus eventBus;
 
-	@Override
-	public void injectActivity(AndroidComponent component) {
-		component.inject(this);
+
+	@Inject
+	public ContactListFragment() {
+
 	}
 
 	@Nullable
@@ -155,7 +147,7 @@ public class ContactListFragment extends BaseEventFragment {
 	@Override
 	public void onResume() {
 		super.onResume();
-
+		eventBus.addListener(this);
 		loadContacts();
 	}
 
@@ -163,6 +155,7 @@ public class ContactListFragment extends BaseEventFragment {
 	public void onPause() {
 		super.onPause();
 		adapter.clear();
+		eventBus.removeListener(this);
 	}
 
 	private void loadContacts() {
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index 5a62bef1f3c378449c2ce8e8ff1178d9aba76fa9..045c58e7f165e4b72ba16e08fa8ed05093624ac5 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -23,6 +23,7 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.api.AndroidNotificationManager;
@@ -157,7 +158,7 @@ public class ConversationActivity extends BriarActivity
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
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..4be89b1085be3057c68b3d6b1b54ce0f078798ae
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/BriarController.java
@@ -0,0 +1,14 @@
+package org.briarproject.android.controller;
+
+
+import org.briarproject.android.controller.handler.ResultHandler;
+
+public interface BriarController extends ActivityLifecycleController {
+	void runOnDbThread(final Runnable task);
+
+	void startAndBindService();
+
+	boolean hasEncryptionKey();
+
+	void signOut(ResultHandler<Void> eventHandler);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd24291c78233b44cdc4c14cb3e61cddf654055a
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/BriarControllerImpl.java
@@ -0,0 +1,118 @@
+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.android.controller.handler.ResultHandler;
+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 BriarControllerImpl implements BriarController {
+
+	private static final Logger LOG =
+			Logger.getLogger(BriarControllerImpl.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 BriarControllerImpl() {
+
+	}
+
+	@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 hasEncryptionKey() {
+		return databaseConfig.getEncryptionKey() != null;
+	}
+
+	@Override
+	public void signOut(final ResultHandler<Void> 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");
+				}
+				eventHandler.onResult(null);
+			}
+		}.start();
+	}
+
+	private 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/controller/ConfigController.java b/briar-android/src/org/briarproject/android/controller/ConfigController.java
new file mode 100644
index 0000000000000000000000000000000000000000..cddbc1bc688e98e21cc7e562175e91d073c52698
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/ConfigController.java
@@ -0,0 +1,9 @@
+package org.briarproject.android.controller;
+
+public interface ConfigController {
+	String getEncryptedDatabaseKey();
+
+	void clearPrefs();
+
+	boolean initialized();
+}
diff --git a/briar-android/src/org/briarproject/android/controller/ConfigControllerImpl.java b/briar-android/src/org/briarproject/android/controller/ConfigControllerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..b823b98e2c879478517211cfedaeceeaa30efa90
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/ConfigControllerImpl.java
@@ -0,0 +1,41 @@
+package org.briarproject.android.controller;
+
+import android.content.SharedPreferences;
+
+import org.briarproject.api.db.DatabaseConfig;
+
+import javax.inject.Inject;
+
+public class ConfigControllerImpl implements ConfigController {
+
+	private final static String PREF_DB_KEY = "key";
+
+	@Inject
+	protected SharedPreferences briarPrefs;
+	@Inject
+	protected volatile DatabaseConfig databaseConfig;
+
+	@Inject
+	public ConfigControllerImpl() {
+
+	}
+
+	public String getEncryptedDatabaseKey() {
+		return briarPrefs.getString(PREF_DB_KEY, null);
+	}
+
+	public void clearPrefs() {
+		SharedPreferences.Editor editor = briarPrefs.edit();
+		editor.clear();
+		editor.apply();
+	}
+
+	@Override
+	public boolean initialized() {
+		String hex = getEncryptedDatabaseKey();
+		if (hex != null && databaseConfig.databaseExists()) {
+			return true;
+		}
+		return false;
+	}
+}
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..56d48b1ca17feddac9c6cf0aa1363864681984dc
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/NavDrawerController.java
@@ -0,0 +1,16 @@
+package org.briarproject.android.controller;
+
+import org.briarproject.android.controller.handler.UiResultHandler;
+import org.briarproject.api.TransportId;
+import org.briarproject.api.identity.LocalAuthor;
+
+public interface NavDrawerController extends BriarController {
+	void setTransportListener(TransportStateListener transportListener);
+
+	boolean isTransportRunning(TransportId transportId);
+
+	void storeLocalAuthor(LocalAuthor author,
+			UiResultHandler<Void> resultHandler);
+
+	LocalAuthor removeAuthorHandle(long handle);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..4be03f94999432a82e25051b354597eefbdc46ab
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/NavDrawerControllerImpl.java
@@ -0,0 +1,136 @@
+package org.briarproject.android.controller;
+
+import android.app.Activity;
+
+import org.briarproject.android.api.ReferenceManager;
+import org.briarproject.android.controller.handler.UiResultHandler;
+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.Logger;
+
+import javax.inject.Inject;
+
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
+
+public class NavDrawerControllerImpl extends BriarControllerImpl
+		implements NavDrawerController, EventListener {
+
+	private static final Logger LOG =
+			Logger.getLogger(NavDrawerControllerImpl.class.getName());
+
+	@Inject
+	protected ReferenceManager referenceManager;
+	@Inject
+	protected volatile IdentityManager identityManager;
+	@Inject
+	protected PluginManager pluginManager;
+	@Inject
+	protected EventBus eventBus;
+	@Inject
+	protected Activity activity;
+
+	private List<Plugin> transports = new ArrayList<Plugin>();
+
+	private TransportStateListener transportStateListener;
+
+	@Inject
+	public NavDrawerControllerImpl() {
+
+	}
+
+	@Override
+	public void onActivityCreate() {
+		super.onActivityCreate();
+	}
+
+	@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);
+				}
+			}
+		});
+	}
+
+	@Override
+	public void setTransportListener(TransportStateListener transportListener) {
+		this.transportStateListener = transportListener;
+	}
+
+	@Override
+	public boolean isTransportRunning(TransportId transportId) {
+		Plugin plugin = pluginManager.getPlugin(transportId);
+		return plugin != null && plugin.isRunning();
+	}
+
+	@Override
+	public void storeLocalAuthor(final LocalAuthor author,
+			final UiResultHandler<Void> 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");
+					resultHandler.onResult(null);
+				} catch (final DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), 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..bf1c9b230ec1349c2fda9f076d6880c7dac1fc6e
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/PasswordController.java
@@ -0,0 +1,8 @@
+package org.briarproject.android.controller;
+
+import org.briarproject.android.controller.handler.ResultHandler;
+
+public interface PasswordController extends ConfigController {
+	void validatePassword(String password,
+			ResultHandler<Boolean> resultHandler);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/PasswordControllerImpl.java b/briar-android/src/org/briarproject/android/controller/PasswordControllerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..12f7e424072860a6853beee0d70542e76b0cb201
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/PasswordControllerImpl.java
@@ -0,0 +1,54 @@
+package org.briarproject.android.controller;
+
+import android.app.Activity;
+
+import org.briarproject.android.controller.handler.ResultHandler;
+import org.briarproject.api.crypto.CryptoComponent;
+import org.briarproject.api.crypto.CryptoExecutor;
+import org.briarproject.api.crypto.SecretKey;
+import org.briarproject.util.StringUtils;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+public class PasswordControllerImpl extends ConfigControllerImpl
+		implements PasswordController {
+
+	@Inject
+	@CryptoExecutor
+	protected Executor cryptoExecutor;
+	@Inject
+	protected CryptoComponent crypto;
+	@Inject
+	protected Activity activity;
+
+	@Inject
+	public PasswordControllerImpl() {
+
+	}
+
+	@Override
+	public void validatePassword(final String password,
+			final ResultHandler<Boolean> resultHandler) {
+		final byte[] encrypted = getEncryptedKey();
+		cryptoExecutor.execute(new Runnable() {
+			public void run() {
+				byte[] key = crypto.decryptWithPassword(encrypted, password);
+				if (key == null) {
+					resultHandler.onResult(false);
+				} else {
+					databaseConfig.setEncryptionKey(new SecretKey(key));
+					resultHandler.onResult(true);
+				}
+			}
+		});
+	}
+
+	private byte[] getEncryptedKey() {
+		String hex = getEncryptedDatabaseKey();
+		if (hex == null)
+			throw new IllegalStateException("Encrypted database key is null.");
+		return StringUtils.fromHexString(hex);
+	}
+}
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..476db0f5e8cefddf5fa661e5ad9249281a768730
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/SetupController.java
@@ -0,0 +1,10 @@
+package org.briarproject.android.controller;
+
+import org.briarproject.android.controller.handler.ResultHandler;
+
+public interface SetupController {
+	float estimatePasswordStrength(String password);
+
+	void createIdentity(String nickname, String password,
+			ResultHandler<Long> resultHandler);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/SetupControllerImpl.java b/briar-android/src/org/briarproject/android/controller/SetupControllerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..29bed6d1940dbe3863666fc9ccd143e60b88b979
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/SetupControllerImpl.java
@@ -0,0 +1,107 @@
+package org.briarproject.android.controller;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+
+import org.briarproject.android.api.ReferenceManager;
+import org.briarproject.android.controller.handler.ResultHandler;
+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.identity.AuthorFactory;
+import org.briarproject.api.identity.LocalAuthor;
+import org.briarproject.util.StringUtils;
+
+import java.util.concurrent.Executor;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+
+import static java.util.logging.Level.INFO;
+
+public class SetupControllerImpl implements SetupController {
+
+	private static final Logger LOG =
+			Logger.getLogger(SetupControllerImpl.class.getName());
+
+	private final static String PREF_DB_KEY = "key";
+
+	@Inject
+	@CryptoExecutor
+	protected Executor cryptoExecutor;
+	@Inject
+	protected PasswordStrengthEstimator strengthEstimator;
+
+	// Fields that are accessed from background threads must be volatile
+	@Inject
+	protected volatile CryptoComponent crypto;
+	@Inject
+	protected volatile DatabaseConfig databaseConfig;
+	@Inject
+	protected volatile AuthorFactory authorFactory;
+	@Inject
+	protected volatile ReferenceManager referenceManager;
+	@Inject
+	protected Activity activity;
+	@Inject
+	protected SharedPreferences briarPrefs;
+
+	@Inject
+	public SetupControllerImpl() {
+
+	}
+
+	private String encryptDatabaseKey(SecretKey key, String password) {
+		long now = System.currentTimeMillis();
+		byte[] encrypted = crypto.encryptWithPassword(key.getBytes(), password);
+		long duration = System.currentTimeMillis() - now;
+		if (LOG.isLoggable(INFO))
+			LOG.info("Key derivation took " + duration + " ms");
+		return StringUtils.toHexString(encrypted);
+	}
+
+	private LocalAuthor createLocalAuthor(String nickname) {
+		long now = System.currentTimeMillis();
+		KeyPair keyPair = crypto.generateSignatureKeyPair();
+		byte[] publicKey = keyPair.getPublic().getEncoded();
+		byte[] privateKey = keyPair.getPrivate().getEncoded();
+		LocalAuthor localAuthor = authorFactory.createLocalAuthor(nickname,
+				publicKey, privateKey);
+		long duration = System.currentTimeMillis() - now;
+		if (LOG.isLoggable(INFO))
+			LOG.info("Identity creation took " + duration + " ms");
+		return localAuthor;
+	}
+
+	@Override
+	public float estimatePasswordStrength(String password) {
+		return strengthEstimator.estimateStrength(password);
+	}
+
+	@Override
+	public void createIdentity(final String nickname, final String password,
+			final ResultHandler<Long> resultHandler) {
+		cryptoExecutor.execute(new Runnable() {
+			public void run() {
+				SecretKey key = crypto.generateSecretKey();
+				databaseConfig.setEncryptionKey(key);
+				String hex = encryptDatabaseKey(key, password);
+				storeEncryptedDatabaseKey(hex);
+				LocalAuthor localAuthor = createLocalAuthor(nickname);
+				long handle = referenceManager.putReference(localAuthor,
+						LocalAuthor.class);
+				resultHandler.onResult(handle);
+			}
+		});
+	}
+
+	private void storeEncryptedDatabaseKey(final String hex) {
+		SharedPreferences.Editor editor = briarPrefs.edit();
+		editor.putString(PREF_DB_KEY, hex);
+		editor.apply();
+	}
+
+}
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/controller/handler/ResultExceptionHandler.java b/briar-android/src/org/briarproject/android/controller/handler/ResultExceptionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d3cb030109f11e730e54c6ff3ecffe2e8667d60
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/handler/ResultExceptionHandler.java
@@ -0,0 +1,6 @@
+package org.briarproject.android.controller.handler;
+
+public interface ResultExceptionHandler<R, E extends Exception> {
+	void onResult(R result);
+	void onException(E exception);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/handler/ResultHandler.java b/briar-android/src/org/briarproject/android/controller/handler/ResultHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..55516f9422162e458633532d60043989dfb6c58b
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/handler/ResultHandler.java
@@ -0,0 +1,5 @@
+package org.briarproject.android.controller.handler;
+
+public interface ResultHandler<R> {
+	void onResult(R result);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java b/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d9c08f4fb2b1ef3ad67f0806186b9b965b292e1
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/handler/UiResultExceptionHandler.java
@@ -0,0 +1,33 @@
+package org.briarproject.android.controller.handler;
+
+import android.app.Activity;
+
+public abstract class UiResultExceptionHandler<R, E extends Exception>
+		implements ResultExceptionHandler<R, E> {
+
+	private final Activity activity;
+
+	public UiResultExceptionHandler(Activity activity) {
+		this.activity = activity;
+	}
+
+	public void onResult(final R result) {
+		activity.runOnUiThread(new Runnable() {
+			public void run() {
+				onResultUi(result);
+			}
+		});
+	}
+
+	public void onException(final E exception) {
+		activity.runOnUiThread(new Runnable() {
+			public void run() {
+				onExceptionUi(exception);
+			}
+		});
+	}
+
+	public abstract void onResultUi(R result);
+
+	public abstract void onExceptionUi(E exception);
+}
diff --git a/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java b/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..1998060a5c9ff4b736f0e4102e3237d19122f4b1
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/controller/handler/UiResultHandler.java
@@ -0,0 +1,22 @@
+package org.briarproject.android.controller.handler;
+
+import android.app.Activity;
+
+public abstract class UiResultHandler<R> implements ResultHandler<R> {
+
+	private final Activity activity;
+
+	public UiResultHandler(Activity activity) {
+		this.activity = activity;
+	}
+
+	public void onResult(final R result) {
+		activity.runOnUiThread(new Runnable() {
+			public void run() {
+				onResultUi(result);
+			}
+		});
+	}
+
+	public abstract void onResultUi(R result);
+}
diff --git a/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java b/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java
index dd7a722e7518cdbf206f410a65b8e8e40f278c95..f1e1a7b9efb6cdee845c4338a0359ef6b122b487 100644
--- a/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/AvailableForumsActivity.java
@@ -5,6 +5,7 @@ import android.support.v7.widget.LinearLayoutManager;
 import android.widget.Toast;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.util.BriarRecyclerView;
@@ -61,7 +62,7 @@ public class AvailableForumsActivity extends BriarActivity
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/forum/ContactSelectorFragment.java b/briar-android/src/org/briarproject/android/forum/ContactSelectorFragment.java
index 73de55ec1817a8f7dff2dde0a87576a1a5b0afca..cd5ff9bcffa3353f5abc0cf94c4b7765e6e2ad82 100644
--- a/briar-android/src/org/briarproject/android/forum/ContactSelectorFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ContactSelectorFragment.java
@@ -13,7 +13,6 @@ import android.view.View;
 import android.view.ViewGroup;
 
 import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.contact.BaseContactListAdapter;
 import org.briarproject.android.contact.ContactListItem;
 import org.briarproject.android.fragment.BaseFragment;
@@ -63,13 +62,15 @@ public class ContactSelectorFragment extends BaseFragment implements
 	@Inject
 	protected volatile ForumSharingManager forumSharingManager;
 
-	public static ContactSelectorFragment newInstance(GroupId groupId) {
-		Bundle args = new Bundle();
-		args.putByteArray(GROUP_ID, groupId.getBytes());
+	public void initBundle(GroupId groupId) {
+		Bundle bundle = new Bundle();
+		bundle.putByteArray(GROUP_ID, groupId.getBytes());
+		setArguments(bundle);
+	}
+
+	@Inject
+	public ContactSelectorFragment() {
 
-		ContactSelectorFragment fragment = new ContactSelectorFragment();
-		fragment.setArguments(args);
-		return fragment;
 	}
 
 	@Override
@@ -83,11 +84,6 @@ public class ContactSelectorFragment extends BaseFragment implements
 		}
 	}
 
-	@Override
-	public void injectActivity(AndroidComponent component) {
-		component.inject(this);
-	}
-
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
diff --git a/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java b/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java
index a35834c93aead75bb04298bae7c94ac1efbfbaee..fbb10650e834a08d2f288279aebd3febb0063253 100644
--- a/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/CreateForumActivity.java
@@ -15,7 +15,7 @@ import android.widget.TextView.OnEditorActionListener;
 import android.widget.Toast;
 
 import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.api.db.DbException;
 import org.briarproject.api.forum.Forum;
@@ -86,7 +86,7 @@ public class CreateForumActivity extends BriarActivity
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/forum/ForumActivity.java b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
index 9a2ec711d9233f87d2a60ad3d643433511de4419..1ea92c3c08b6c73d5c66def586d8796908042c0e 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumActivity.java
@@ -19,6 +19,7 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.api.AndroidNotificationManager;
@@ -127,7 +128,7 @@ public class ForumActivity extends BriarActivity implements EventListener,
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
index 4aa853bd7e42dc5d04db6037ac689543c41566fd..0129990936a525b30ee901014cec39cb06faa345 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListFragment.java
@@ -14,6 +14,7 @@ import android.view.View;
 import android.view.ViewGroup;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.fragment.BaseEventFragment;
 import org.briarproject.android.util.BriarRecyclerView;
@@ -50,14 +51,6 @@ public class ForumListFragment extends BaseEventFragment implements
 	private static final Logger LOG =
 			Logger.getLogger(ForumListFragment.class.getName());
 
-	public static ForumListFragment newInstance() {
-
-		Bundle args = new Bundle();
-
-		ForumListFragment fragment = new ForumListFragment();
-		fragment.setArguments(args);
-		return fragment;
-	}
 
 	private BriarRecyclerView list;
 	private ForumListAdapter adapter;
@@ -67,6 +60,11 @@ public class ForumListFragment extends BaseEventFragment implements
 	@Inject protected volatile ForumManager forumManager;
 	@Inject protected volatile ForumSharingManager forumSharingManager;
 
+	@Inject
+	public ForumListFragment() {
+
+	}
+
 	@Nullable
 	@Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -99,11 +97,6 @@ public class ForumListFragment extends BaseEventFragment implements
 		return TAG;
 	}
 
-	@Override
-	public void injectActivity(AndroidComponent component) {
-		component.inject(this);
-	}
-
 	@Override
 	public void onResume() {
 		super.onResume();
diff --git a/briar-android/src/org/briarproject/android/forum/ReadForumPostActivity.java b/briar-android/src/org/briarproject/android/forum/ReadForumPostActivity.java
index f320ed6efd14a776d2f94c210846d53d82817438..cfc80ace2a4a4363327a4c88b3115bdc6cecbf64 100644
--- a/briar-android/src/org/briarproject/android/forum/ReadForumPostActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/ReadForumPostActivity.java
@@ -12,6 +12,7 @@ import android.widget.ScrollView;
 import android.widget.TextView;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.util.AuthorView;
@@ -168,7 +169,7 @@ implements OnClickListener {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java b/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java
index 820e25666fdf0a26d0644a2ffa25cb0031aeb0dc..81bcdf8cd7025b179a4a4ba66ab36768926db478 100644
--- a/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java
@@ -5,7 +5,7 @@ import android.os.Bundle;
 import android.view.View;
 
 import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.api.contact.ContactId;
@@ -33,7 +33,8 @@ public class ShareForumActivity extends BriarActivity implements
 
 		if (savedInstanceState == null) {
 			ContactSelectorFragment contactSelectorFragment =
-					ContactSelectorFragment.newInstance(groupId);
+					activityComponent.newContactSelectorFragment();
+			contactSelectorFragment.initBundle(groupId);
 			getSupportFragmentManager().beginTransaction()
 					.add(R.id.shareForumContainer, contactSelectorFragment)
 					.commit();
@@ -41,7 +42,7 @@ public class ShareForumActivity extends BriarActivity implements
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
@@ -49,7 +50,8 @@ public class ShareForumActivity extends BriarActivity implements
 			Collection<ContactId> contacts) {
 
 		ShareForumMessageFragment messageFragment =
-				ShareForumMessageFragment.newInstance(groupId, contacts);
+				activityComponent.newShareForumMessageFragment();
+		messageFragment.initBundle(groupId, contacts);
 
 		getSupportFragmentManager().beginTransaction()
 				.setCustomAnimations(android.R.anim.fade_in,
diff --git a/briar-android/src/org/briarproject/android/forum/ShareForumMessageFragment.java b/briar-android/src/org/briarproject/android/forum/ShareForumMessageFragment.java
index 7ed79d67cde563f0669adb6afde95095fbed7b51..ab2586666e9df61356badaec563bac9c78c5e23f 100644
--- a/briar-android/src/org/briarproject/android/forum/ShareForumMessageFragment.java
+++ b/briar-android/src/org/briarproject/android/forum/ShareForumMessageFragment.java
@@ -13,7 +13,6 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.db.DbException;
@@ -45,17 +44,16 @@ public class ShareForumMessageFragment extends BaseFragment {
 	private volatile GroupId groupId;
 	private volatile Collection<ContactId> contacts;
 
-	public static ShareForumMessageFragment newInstance(GroupId groupId,
-			Collection<ContactId> contacts) {
-
-		ShareForumMessageFragment f = new ShareForumMessageFragment();
+	public void initBundle(GroupId groupId, Collection<ContactId> contacts) {
+		Bundle bundle = new Bundle();
+		bundle.putByteArray(GROUP_ID, groupId.getBytes());
+		bundle.putIntegerArrayList(CONTACTS, getContactsFromIds(contacts));
+		setArguments(bundle);
+	}
 
-		Bundle args = new Bundle();
-		args.putByteArray(GROUP_ID, groupId.getBytes());
-		args.putIntegerArrayList(CONTACTS, getContactsFromIds(contacts));
-		f.setArguments(args);
+	@Inject
+	public ShareForumMessageFragment() {
 
-		return f;
 	}
 
 	@Override
@@ -69,11 +67,6 @@ public class ShareForumMessageFragment extends BaseFragment {
 		}
 	}
 
-	@Override
-	public void injectActivity(AndroidComponent component) {
-		component.inject(this);
-	}
-
 	@Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
 			Bundle savedInstanceState) {
diff --git a/briar-android/src/org/briarproject/android/forum/WriteForumPostActivity.java b/briar-android/src/org/briarproject/android/forum/WriteForumPostActivity.java
index 4087115e036c5598709903df94dd337e5959e5e2..d2185aa4630df3d1dcd024fd322a6c4bcdd154dd 100644
--- a/briar-android/src/org/briarproject/android/forum/WriteForumPostActivity.java
+++ b/briar-android/src/org/briarproject/android/forum/WriteForumPostActivity.java
@@ -16,6 +16,7 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.identity.CreateIdentityActivity;
@@ -161,7 +162,7 @@ implements OnItemSelectedListener, OnClickListener {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java b/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java
index f353b6e08dddc6c4862fc21a531b0b591f14dcf1..69ceab43a6281a5a7ae1f0ad901697a6b2651d82 100644
--- a/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java
+++ b/briar-android/src/org/briarproject/android/fragment/BaseEventFragment.java
@@ -5,9 +5,6 @@ import org.briarproject.api.event.EventListener;
 
 import javax.inject.Inject;
 
-/**
- * Created by Ernir Erlingsson (ernir@ymirmobile.com) on 8.1.2016.
- */
 public abstract class BaseEventFragment extends BaseFragment implements
 		EventListener {
 
diff --git a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java
index 494f93c2dbfb2a74f2b4188a15ba96c8a1c7ef83..96efaad58c2a7201c795daefaf66d3dd326d2ba1 100644
--- a/briar-android/src/org/briarproject/android/fragment/BaseFragment.java
+++ b/briar-android/src/org/briarproject/android/fragment/BaseFragment.java
@@ -4,9 +4,6 @@ import android.content.Context;
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
 
-import org.briarproject.android.AndroidComponent;
-import org.briarproject.android.BriarApplication;
-
 public abstract class BaseFragment extends Fragment {
 
 	public abstract String getUniqueTag();
@@ -27,16 +24,9 @@ public abstract class BaseFragment extends Fragment {
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
-
-		BriarApplication application =
-				(BriarApplication) getActivity().getApplication();
-		injectActivity(application.getApplicationComponent());
 	}
 
-	public abstract void injectActivity(AndroidComponent component);
-
 	public interface BaseFragmentListener {
-
 		void showLoadingScreen(boolean isBlocking, int stringId);
 
 		void hideLoadingScreen();
@@ -45,4 +35,5 @@ public abstract class BaseFragment extends Fragment {
 
 		void runOnDbThread(Runnable runnable);
 	}
+
 }
diff --git a/briar-android/src/org/briarproject/android/fragment/DashboardFragment.java b/briar-android/src/org/briarproject/android/fragment/DashboardFragment.java
deleted file mode 100644
index f98c16ab08336ebfc98b50e94fca9fa2dca5ef51..0000000000000000000000000000000000000000
--- a/briar-android/src/org/briarproject/android/fragment/DashboardFragment.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package org.briarproject.android.fragment;
-
-
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.GridView;
-
-import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
-import org.briarproject.api.event.Event;
-import org.briarproject.api.plugins.PluginManager;
-
-import java.util.logging.Logger;
-
-import javax.inject.Inject;
-
-public class DashboardFragment extends BaseEventFragment {
-
-	public final static String TAG = "DashboardFragment";
-
-	private static final Logger LOG =
-			Logger.getLogger(DashboardFragment.class.getName());
-
-	@Inject
-	protected PluginManager pluginManager;
-
-	public static DashboardFragment newInstance() {
-
-		Bundle args = new Bundle();
-
-		DashboardFragment fragment = new DashboardFragment();
-		fragment.setArguments(args);
-		return fragment;
-	}
-
-	@Nullable
-	@Override
-	public View onCreateView(LayoutInflater inflater, ViewGroup container,
-			Bundle savedInstanceState) {
-		View contentView =
-				inflater.inflate(R.layout.fragment_dashboard, container, false);
-		return contentView;
-	}
-
-	@Override
-	public void onViewCreated(View view, Bundle savedInstanceState) {
-		super.onViewCreated(view, savedInstanceState);
-	}
-
-	@Override
-	public String getUniqueTag() {
-		return TAG;
-	}
-
-	@Override
-	public void injectActivity(AndroidComponent component) {
-
-	}
-
-	@Override
-	public void eventOccurred(Event e) {
-
-	}
-}
diff --git a/briar-android/src/org/briarproject/android/identity/CreateIdentityActivity.java b/briar-android/src/org/briarproject/android/identity/CreateIdentityActivity.java
index d1d37f9facfcf74e757fba257fb2692755ec410d..b95ca581fcb5879bc198e345f0f25c07c2d8e53a 100644
--- a/briar-android/src/org/briarproject/android/identity/CreateIdentityActivity.java
+++ b/briar-android/src/org/briarproject/android/identity/CreateIdentityActivity.java
@@ -14,6 +14,7 @@ import android.widget.TextView.OnEditorActionListener;
 import android.widget.Toast;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.util.LayoutUtils;
@@ -114,7 +115,7 @@ implements OnEditorActionListener, OnClickListener {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java
index 11e30d6356ab9bfe2b27dffae8a251dc28a88d6d..7b1bcbb5cb90c6465841adf142e066ee8119e3e3 100644
--- a/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java
+++ b/briar-android/src/org/briarproject/android/introduction/ContactChooserFragment.java
@@ -12,7 +12,6 @@ import android.view.View;
 import android.view.ViewGroup;
 
 import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.contact.ContactListAdapter;
 import org.briarproject.android.contact.ContactListItem;
 import org.briarproject.android.contact.ConversationItem;
@@ -66,6 +65,11 @@ public class ContactChooserFragment extends BaseFragment {
 	@Inject
 	protected volatile ConnectionRegistry connectionRegistry;
 
+	@Inject
+	public ContactChooserFragment() {
+
+	}
+
 	@Override
 	public void onAttach(Context context) {
 		super.onAttach(context);
@@ -77,11 +81,6 @@ public class ContactChooserFragment extends BaseFragment {
 		}
 	}
 
-	@Override
-	public void injectActivity(AndroidComponent component) {
-		component.inject(this);
-	}
-
 	@Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
 			Bundle savedInstanceState) {
diff --git a/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java b/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java
index 2faee1a8ab22b30d7757d91702bca976a796eb6a..79d511291f0065a8db188f480b819e7a373116e3 100644
--- a/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java
+++ b/briar-android/src/org/briarproject/android/introduction/IntroductionActivity.java
@@ -3,6 +3,7 @@ package org.briarproject.android.introduction;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
+import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.transition.ChangeBounds;
 import android.transition.Fade;
@@ -10,7 +11,7 @@ import android.view.MenuItem;
 import android.view.View;
 
 import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.api.contact.Contact;
@@ -33,15 +34,15 @@ public class IntroductionActivity extends BriarActivity implements
 		setContentView(R.layout.activity_introduction);
 
 		if (savedInstanceState == null) {
-			ContactChooserFragment chooserFragment =
-					new ContactChooserFragment();
 			getSupportFragmentManager().beginTransaction()
-					.add(R.id.introductionContainer, chooserFragment).commit();
+					.add(R.id.introductionContainer,
+							activityComponent.newContactChooserFragment())
+					.commit();
 		}
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
@@ -85,13 +86,14 @@ public class IntroductionActivity extends BriarActivity implements
 			final Contact c2) {
 
 		IntroductionMessageFragment messageFragment =
-				IntroductionMessageFragment
-						.newInstance(c1.getId().getInt(), c2.getId().getInt());
+				activityComponent.newIntroductionMessageFragment();
+		messageFragment.initBundle(c1.getId().getInt(), c2.getId().getInt());
 
 		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
 			messageFragment.setSharedElementEnterTransition(new ChangeBounds());
 			messageFragment.setEnterTransition(new Fade());
-			messageFragment.setSharedElementReturnTransition(new ChangeBounds());
+			messageFragment
+					.setSharedElementReturnTransition(new ChangeBounds());
 		}
 
 		getSupportFragmentManager().beginTransaction()
diff --git a/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java b/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java
index ed0547da4e0b9eb8b69e7c8d6ea7433ba392e0b6..48f0726c086d49de467bacbb17a9ff3ec483ea6e 100644
--- a/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java
+++ b/briar-android/src/org/briarproject/android/introduction/IntroductionMessageFragment.java
@@ -13,7 +13,6 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.api.FormatException;
 import org.briarproject.api.contact.Contact;
@@ -49,18 +48,19 @@ public class IntroductionMessageFragment extends BaseFragment {
 	@Inject
 	protected volatile IntroductionManager introductionManager;
 
-	public static IntroductionMessageFragment newInstance(int contactId1,
-			int contactId2) {
-		IntroductionMessageFragment f = new IntroductionMessageFragment();
-
+	public void initBundle(int contactId1, int contactId2) {
 		Bundle args = new Bundle();
 		args.putInt(CONTACT_ID_1, contactId1);
 		args.putInt(CONTACT_ID_2, contactId2);
-		f.setArguments(args);
+		setArguments(args);
+	}
+
+	@Inject
+	public IntroductionMessageFragment() {
 
-		return f;
 	}
 
+
 	@Override
 	public void onAttach(Context context) {
 		super.onAttach(context);
@@ -72,11 +72,6 @@ public class IntroductionMessageFragment extends BaseFragment {
 		}
 	}
 
-	@Override
-	public void injectActivity(AndroidComponent component) {
-		component.inject(this);
-	}
-
 	@Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
 			Bundle savedInstanceState) {
@@ -183,7 +178,8 @@ public class IntroductionMessageFragment extends BaseFragment {
 				// actually make the introduction
 				try {
 					long timestamp = System.currentTimeMillis();
-					introductionManager.makeIntroduction(c1, c2, msg, timestamp);
+					introductionManager
+							.makeIntroduction(c1, c2, msg, timestamp);
 				} catch (DbException e) {
 					if (LOG.isLoggable(WARNING))
 						LOG.log(WARNING, e.toString(), e);
diff --git a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
index 2faf5f6193f074e43bc0c43d56794b42fb26365e..acd8d36a14b4259ab09b09ad201ba00b62c98301 100644
--- a/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
+++ b/briar-android/src/org/briarproject/android/invitation/AddContactActivity.java
@@ -5,7 +5,7 @@ import android.os.Bundle;
 import android.widget.Toast;
 
 import org.briarproject.R;
-import org.briarproject.android.AndroidComponent;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.api.ReferenceManager;
 import org.briarproject.api.crypto.CryptoComponent;
@@ -145,7 +145,7 @@ implements InvitationListener {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/keyagreement/ChooseIdentityFragment.java b/briar-android/src/org/briarproject/android/keyagreement/ChooseIdentityFragment.java
index 16818d36a83d84a1159a651eee0cbc5a582c2c82..40206766ed660e72b846596dd34cc57c8493aa55 100644
--- a/briar-android/src/org/briarproject/android/keyagreement/ChooseIdentityFragment.java
+++ b/briar-android/src/org/briarproject/android/keyagreement/ChooseIdentityFragment.java
@@ -13,6 +13,7 @@ import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.Spinner;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.fragment.BaseFragment;
 import org.briarproject.android.identity.CreateIdentityActivity;
@@ -59,11 +60,9 @@ public class ChooseIdentityFragment extends BaseFragment
 	@Inject
 	protected volatile IdentityManager identityManager;
 
-	public static ChooseIdentityFragment newInstance() {
-		Bundle args = new Bundle();
-		ChooseIdentityFragment fragment = new ChooseIdentityFragment();
-		fragment.setArguments(args);
-		return fragment;
+	@Inject
+	public ChooseIdentityFragment() {
+
 	}
 
 	@Override
@@ -82,11 +81,6 @@ public class ChooseIdentityFragment extends BaseFragment
 		return TAG;
 	}
 
-	@Override
-	public void injectActivity(AndroidComponent component) {
-		component.inject(this);
-	}
-
 	@Nullable
 	@Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
diff --git a/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java b/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java
index 185d3c0b1efc3d4f14daca2d1b312d417a79aadb..b2395eaa2fe985529914fe17384c434361c6d711 100644
--- a/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java
+++ b/briar-android/src/org/briarproject/android/keyagreement/KeyAgreementActivity.java
@@ -7,6 +7,7 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarFragmentActivity;
 import org.briarproject.android.fragment.BaseFragment;
@@ -63,7 +64,7 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
 	protected volatile IdentityManager identityManager;
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
@@ -96,11 +97,11 @@ public class KeyAgreementActivity extends BriarFragmentActivity implements
 						STEPS));
 		switch (step) {
 			case STEP_QR:
-				startFragment(ShowQrCodeFragment.newInstance());
+				startFragment(activityComponent.newShowQrCodeFragment());
 				break;
 			case STEP_ID:
 			default:
-				startFragment(ChooseIdentityFragment.newInstance());
+				startFragment(activityComponent.newChooseIdentityFragment());
 				break;
 		}
 	}
diff --git a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java
index cbe175d8e124c968002e17b3e2184a287485bb88..8a997168d94403c77ad8395fef40d11b1af9f1d4 100644
--- a/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java
+++ b/briar-android/src/org/briarproject/android/keyagreement/ShowQrCodeFragment.java
@@ -86,11 +86,9 @@ public class ShowQrCodeFragment extends BaseEventFragment
 	private volatile KeyAgreementTask task;
 	private volatile boolean waitingForBluetooth;
 
-	public static ShowQrCodeFragment newInstance() {
-		Bundle args = new Bundle();
-		ShowQrCodeFragment fragment = new ShowQrCodeFragment();
-		fragment.setArguments(args);
-		return fragment;
+	@Inject
+	public ShowQrCodeFragment() {
+
 	}
 
 	@Override
@@ -98,11 +96,6 @@ public class ShowQrCodeFragment extends BaseEventFragment
 		return TAG;
 	}
 
-	@Override
-	public void injectActivity(AndroidComponent component) {
-		component.inject(this);
-	}
-
 	@Nullable
 	@Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
diff --git a/briar-android/src/org/briarproject/android/panic/ExitActivity.java b/briar-android/src/org/briarproject/android/panic/ExitActivity.java
index 4417c1fe8f8500ea9c85fa46f748c984979dcc7d..7e85402018ee18a2c7bb901439cea1dfa7a5337f 100644
--- a/briar-android/src/org/briarproject/android/panic/ExitActivity.java
+++ b/briar-android/src/org/briarproject/android/panic/ExitActivity.java
@@ -3,6 +3,7 @@ package org.briarproject.android.panic;
 import android.os.Build;
 import android.os.Bundle;
 
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BaseActivity;
 
@@ -23,7 +24,7 @@ public class ExitActivity extends BaseActivity {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 
 	}
 }
\ No newline at end of file
diff --git a/briar-android/src/org/briarproject/android/panic/PanicPreferencesActivity.java b/briar-android/src/org/briarproject/android/panic/PanicPreferencesActivity.java
index c25461c347476556401f09c57da3264b724112ec..f0645f3c2ed495066ab7d0b67cb536fc8f2c4e3e 100644
--- a/briar-android/src/org/briarproject/android/panic/PanicPreferencesActivity.java
+++ b/briar-android/src/org/briarproject/android/panic/PanicPreferencesActivity.java
@@ -5,6 +5,7 @@ import android.support.v7.app.ActionBar;
 import android.view.MenuItem;
 
 import org.briarproject.R;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.AndroidComponent;
 import org.briarproject.android.BriarActivity;
 
@@ -24,7 +25,7 @@ public class PanicPreferencesActivity extends BriarActivity {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
diff --git a/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java b/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java
index 87ba49e7023eada4ff2051e63baed477500d75a4..fbe549e6ee0cd1c17eca51d0da70966ec2373bf5 100644
--- a/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java
+++ b/briar-android/src/org/briarproject/android/panic/PanicResponderActivity.java
@@ -7,11 +7,11 @@ import android.os.Build;
 import android.os.Bundle;
 import android.support.v7.preference.PreferenceManager;
 
-import org.briarproject.android.AndroidComponent;
+import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.BriarActivity;
 import org.briarproject.android.api.AndroidExecutor;
+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,9 +32,7 @@ public class PanicResponderActivity extends BriarActivity {
 
 	private static final Logger LOG =
 			Logger.getLogger(PanicResponderActivity.class.getName());
-
-	@Inject
-	protected DatabaseConfig databaseConfig;
+	@Inject protected ConfigController configController;
 	@Inject
 	protected AndroidExecutor androidExecutor;
 
@@ -105,15 +103,16 @@ public class PanicResponderActivity extends BriarActivity {
 	}
 
 	@Override
-	public void injectActivity(AndroidComponent component) {
+	public void injectActivity(ActivityComponent component) {
 		component.inject(this);
 	}
 
 	private void deleteAllData() {
 		androidExecutor.execute(new Runnable() {
 			public void run() {
-				clearSharedPrefs();
+				configController.clearPrefs();
 				// TODO somehow delete/shred the database more thoroughly
+				// TODO replace this static call with a controller method
 				AndroidUtils.deleteAppData(PanicResponderActivity.this);
 				PanicResponder.deleteAllAppData(PanicResponderActivity.this);
 
diff --git a/briar-android/src/org/briarproject/android/util/StrengthMeter.java b/briar-android/src/org/briarproject/android/util/StrengthMeter.java
index eee1e547396ed6d466c9afce4764c3145ede77c1..83fb20b8f1221916ca97f4b95d633376507b891e 100644
--- a/briar-android/src/org/briarproject/android/util/StrengthMeter.java
+++ b/briar-android/src/org/briarproject/android/util/StrengthMeter.java
@@ -23,11 +23,11 @@ import static org.briarproject.api.crypto.PasswordStrengthEstimator.WEAK;
 public class StrengthMeter extends ProgressBar {
 
 	private static final int MAX = 100;
-	private static final int RED = Color.rgb(255, 0, 0);
-	private static final int ORANGE = Color.rgb(255, 160, 0);
-	private static final int YELLOW = Color.rgb(255, 255, 0);
-	private static final int LIME = Color.rgb(180, 255, 0);
-	private static final int GREEN = Color.rgb(0, 255, 0);
+	public static final int RED = Color.rgb(255, 0, 0);
+	public static final int ORANGE = Color.rgb(255, 160, 0);
+	public static final int YELLOW = Color.rgb(255, 255, 0);
+	public static final int LIME = Color.rgb(180, 255, 0);
+	public static final int GREEN = Color.rgb(0, 255, 0);
 
 	private final ShapeDrawable bar;
 
@@ -57,6 +57,10 @@ public class StrengthMeter extends ProgressBar {
 		return MAX;
 	}
 
+	public int getColor() {
+		return bar.getPaint().getColor();
+	}
+
 	public void setStrength(float strength) {
 		if (strength < 0 || strength > 1) throw new IllegalArgumentException();
 		int colour;
diff --git a/briar-android/src/org/briarproject/system/AndroidSeedProvider.java b/briar-android/src/org/briarproject/system/AndroidSeedProvider.java
index c15e0b411a1efdb7e5805ea1e85acee4a4168592..59c7a6e3a5bc8f25d52d909c5a979af320f61409 100644
--- a/briar-android/src/org/briarproject/system/AndroidSeedProvider.java
+++ b/briar-android/src/org/briarproject/system/AndroidSeedProvider.java
@@ -8,6 +8,7 @@ import android.provider.Settings;
 
 import java.io.DataOutputStream;
 import java.io.IOException;
+import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
@@ -15,6 +16,9 @@ import static android.provider.Settings.Secure.ANDROID_ID;
 
 class AndroidSeedProvider extends LinuxSeedProvider {
 
+	private static final Logger LOG =
+			Logger.getLogger(LinuxSeedProvider.class.getName());
+
 	private final Context appContext;
 
 	@Inject
@@ -30,7 +34,10 @@ class AndroidSeedProvider extends LinuxSeedProvider {
 		if (Build.FINGERPRINT != null) out.writeUTF(Build.FINGERPRINT);
 		if (Build.SERIAL != null) out.writeUTF(Build.SERIAL);
 		ContentResolver contentResolver = appContext.getContentResolver();
-		out.writeUTF(Settings.Secure.getString(contentResolver, ANDROID_ID));
+		String str = Settings.Secure.getString(contentResolver, ANDROID_ID);
+		if (str != null) {
+			out.writeUTF(str);
+		}
 		super.writeToEntropyPool(out);
 	}
 }
diff --git a/briar-android/test/java/android/net/http/AndroidHttpClient.java b/briar-android/test/java/android/net/http/AndroidHttpClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2cf7a34632bbf4e3a5ef2220ac8a9d01e0da1da
--- /dev/null
+++ b/briar-android/test/java/android/net/http/AndroidHttpClient.java
@@ -0,0 +1,7 @@
+package android.net.http;
+
+// This class is here to fix an issue with Robolectric.
+// https://github.com/robolectric/robolectric/issues/1862
+// TODO Check if this class can be removed on next Robolectric update
+public class AndroidHttpClient {
+}
\ No newline at end of file
diff --git a/briar-android/test/java/briarproject/activity/SetupActivityTest.java b/briar-android/test/java/briarproject/activity/SetupActivityTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b58d033b25b53394602b52d00dd4836242a10717
--- /dev/null
+++ b/briar-android/test/java/briarproject/activity/SetupActivityTest.java
@@ -0,0 +1,229 @@
+package briarproject.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.support.design.widget.TextInputLayout;
+import android.widget.Button;
+import android.widget.EditText;
+
+import com.google.common.base.Strings;
+
+import org.briarproject.BuildConfig;
+import org.briarproject.R;
+import org.briarproject.android.NavDrawerActivity;
+import org.briarproject.android.controller.SetupController;
+import org.briarproject.android.controller.handler.ResultHandler;
+import org.briarproject.android.util.StrengthMeter;
+import org.briarproject.api.identity.AuthorConstants;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricGradleTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowActivity;
+
+import static junit.framework.Assert.assertEquals;
+import static org.briarproject.api.crypto.PasswordStrengthEstimator.NONE;
+import static org.briarproject.api.crypto.PasswordStrengthEstimator.QUITE_STRONG;
+import static org.briarproject.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
+import static org.briarproject.api.crypto.PasswordStrengthEstimator.STRONG;
+import static org.briarproject.api.crypto.PasswordStrengthEstimator.WEAK;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
+
+@RunWith(RobolectricGradleTestRunner.class)
+@Config(constants = BuildConfig.class, sdk = 21,
+		application = TestBriarApplicationImp.class)
+public class SetupActivityTest {
+
+	TestSetupActivity setupActivity;
+	TextInputLayout nicknameEntryWrapper;
+	TextInputLayout passwordEntryWrapper;
+	TextInputLayout passwordConfirmationWrapper;
+	EditText nicknameEntry;
+	EditText passwordEntry;
+	EditText passwordConfirmation;
+	StrengthMeter strengthMeter;
+	Button createAccountButton;
+
+	@Mock
+	SetupController setupController;
+	@Captor
+	ArgumentCaptor<ResultHandler<Long>> resultCaptor;
+
+	@Before
+	public void setUp() {
+		MockitoAnnotations.initMocks(this);
+		setupActivity = Robolectric.setupActivity(TestSetupActivity.class);
+		nicknameEntryWrapper = (TextInputLayout) setupActivity
+				.findViewById(R.id.nickname_entry_wrapper);
+		passwordEntryWrapper = (TextInputLayout) setupActivity
+				.findViewById(R.id.password_entry_wrapper);
+		passwordConfirmationWrapper = (TextInputLayout) setupActivity
+				.findViewById(R.id.password_confirm_wrapper);
+		nicknameEntry =
+				(EditText) setupActivity.findViewById(R.id.nickname_entry);
+		passwordEntry =
+				(EditText) setupActivity.findViewById(R.id.password_entry);
+		passwordConfirmation =
+				(EditText) setupActivity.findViewById(R.id.password_confirm);
+		strengthMeter =
+				(StrengthMeter) setupActivity.findViewById(R.id.strength_meter);
+		createAccountButton =
+				(Button) setupActivity.findViewById(R.id.create_account);
+	}
+
+	private void testStrengthMeter(String pass, float strength, int color) {
+		passwordEntry.setText(pass);
+		assertEquals(strengthMeter.getProgress(),
+				(int) (strengthMeter.getMax() * strength));
+		assertEquals(color, strengthMeter.getColor());
+	}
+
+	@Test
+	public void testPasswordMatchUI() {
+		// Password mismatch
+		passwordEntry.setText("really.safe.password");
+		passwordConfirmation.setText("really.safe.pass");
+		assertEquals(createAccountButton.isEnabled(), false);
+		assertEquals(passwordConfirmationWrapper.getError(),
+				setupActivity.getString(R.string.passwords_do_not_match));
+		// Button enabled
+		passwordEntry.setText("really.safe.pass");
+		passwordConfirmation.setText("really.safe.pass");
+		// Confirm that the password mismatch error message is not visible
+		Assert.assertNotEquals(passwordConfirmationWrapper.getError(),
+				setupActivity.getString(R.string.passwords_do_not_match));
+		// Nick has not been set, expect the button to be disabled
+		assertEquals(createAccountButton.isEnabled(), false);
+	}
+
+	@Test
+	public void testCreateAccountUI() {
+
+		SetupController mockedController = this.setupController;
+		setupActivity.setController(mockedController);
+		// Mock strong password strength answer
+		when(mockedController.estimatePasswordStrength(anyString())).thenReturn(
+				STRONG);
+		String safePass = "really.safe.password";
+		String nick = "nick.nickerton";
+		passwordEntry.setText(safePass);
+		passwordConfirmation.setText(safePass);
+		nicknameEntry.setText(nick);
+		// Confirm that the create account button is clickable
+		assertEquals(createAccountButton.isEnabled(), true);
+		createAccountButton.performClick();
+		// Verify that the controller's method was called with the correct
+		// params and get the callback
+		verify(mockedController, times(1))
+				.createIdentity(eq(nick), eq(safePass), resultCaptor.capture());
+		// execute the callback
+		resultCaptor.getValue().onResult(1L);
+		assertEquals(setupActivity.isFinishing(), true);
+		// Confirm that the correct Activity has been started
+		ShadowActivity shadowActivity = shadowOf(setupActivity);
+		Intent intent = shadowActivity.peekNextStartedActivity();
+		assertEquals(intent.getComponent().getClassName(),
+				NavDrawerActivity.class.getName());
+	}
+
+	@Test
+	public void testNicknameUI() {
+		Assert.assertNotNull(setupActivity);
+		String longNick =
+				Strings.padEnd("*", AuthorConstants.MAX_AUTHOR_NAME_LENGTH + 1,
+						'*');
+		nicknameEntry.setText(longNick);
+		// Nickname should be too long
+		assertEquals(nicknameEntryWrapper.getError(),
+				setupActivity.getString(R.string.name_too_long));
+	}
+
+	@Test
+	public void testAccountCreation() {
+		SetupController controller = setupActivity.getController();
+		// mock a resulthandler
+		ResultHandler<Long> resultHandler =
+				(ResultHandler<Long>) mock(ResultHandler.class);
+		controller
+				.createIdentity("nick", "some.strong.pass", resultHandler);
+		// blocking verification call with timeout that waits until the mocked
+		// result gets called with handle 0L, the expected value
+		verify(resultHandler, timeout(2000).times(1)).onResult(0L);
+		SharedPreferences prefs =
+				setupActivity.getSharedPreferences("db", Context.MODE_PRIVATE);
+		// Confirm database key
+		assertTrue(prefs.contains("key"));
+		// Note that Robolectric uses its own persistant storage that it
+		// wipes clean after each test run, no need to clean up manually.
+	}
+
+	@Test
+	public void testStrengthMeter() {
+		SetupController controller = setupActivity.getController();
+
+		String strongPass = "very.strong.password.123";
+		String weakPass = "we";
+		String quiteStrongPass = "quite.strong";
+
+		float val = controller.estimatePasswordStrength(strongPass);
+		assertTrue(val == STRONG);
+		val = controller.estimatePasswordStrength(weakPass);
+		assertTrue(val < WEAK && val > NONE);
+		val = controller.estimatePasswordStrength(quiteStrongPass);
+		assertTrue(val < STRONG && val > QUITE_WEAK);
+	}
+
+	@Test
+	public void testStrengthMeterUI() {
+		Assert.assertNotNull(setupActivity);
+		// replace the setup controller with our mocked copy
+		SetupController mockedController = this.setupController;
+		setupActivity.setController(mockedController);
+		// Mock answers for UI testing only
+		when(mockedController.estimatePasswordStrength("strong")).thenReturn(
+				STRONG);
+		when(mockedController.estimatePasswordStrength("qstring")).thenReturn(
+				QUITE_STRONG);
+		when(mockedController.estimatePasswordStrength("qweak")).thenReturn(
+				QUITE_WEAK);
+		when(mockedController.estimatePasswordStrength("weak")).thenReturn(
+				WEAK);
+		when(mockedController.estimatePasswordStrength("empty")).thenReturn(
+				NONE);
+		// Test the meters progress and color for several values
+		testStrengthMeter("strong", STRONG, StrengthMeter.GREEN);
+		Mockito.verify(mockedController, Mockito.times(1))
+				.estimatePasswordStrength(eq("strong"));
+		testStrengthMeter("qstring", QUITE_STRONG, StrengthMeter.LIME);
+		Mockito.verify(mockedController, Mockito.times(1))
+				.estimatePasswordStrength(eq("qstring"));
+		testStrengthMeter("qweak", QUITE_WEAK, StrengthMeter.YELLOW);
+		Mockito.verify(mockedController, Mockito.times(1))
+				.estimatePasswordStrength(eq("qweak"));
+		testStrengthMeter("weak", WEAK, StrengthMeter.ORANGE);
+		Mockito.verify(mockedController, Mockito.times(1))
+				.estimatePasswordStrength(eq("weak"));
+		// Not sure this should be the correct behaviour on an empty input ?
+		testStrengthMeter("empty", NONE, StrengthMeter.RED);
+		Mockito.verify(mockedController, Mockito.times(1))
+				.estimatePasswordStrength(eq("empty"));
+	}
+
+}
diff --git a/briar-android/test/java/briarproject/activity/TestBriarApplicationImp.java b/briar-android/test/java/briarproject/activity/TestBriarApplicationImp.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e29d9efd238946a641c836aec944196f7ddd97c
--- /dev/null
+++ b/briar-android/test/java/briarproject/activity/TestBriarApplicationImp.java
@@ -0,0 +1,43 @@
+package briarproject.activity;
+
+import android.app.Application;
+
+import org.briarproject.CoreModule;
+import org.briarproject.android.AndroidComponent;
+import org.briarproject.android.AndroidEagerSingletons;
+import org.briarproject.android.AppModule;
+import org.briarproject.android.BriarApplication;
+import org.briarproject.android.DaggerAndroidComponent;
+
+import java.util.logging.Logger;
+
+/**
+ * This Class only exists to get around ACRA
+ */
+public class TestBriarApplicationImp extends Application implements
+		BriarApplication{
+
+	private static final Logger LOG =
+			Logger.getLogger(TestBriarApplicationImp.class.getName());
+
+	private AndroidComponent applicationComponent;
+
+	@Override
+	public void onCreate() {
+		super.onCreate();
+		LOG.info("Created");
+
+		applicationComponent = DaggerAndroidComponent.builder()
+				.appModule(new AppModule(this))
+				.build();
+
+		// We need to load the eager singletons directly after making the
+		// dependency graphs
+		CoreModule.initEagerSingletons(applicationComponent);
+		AndroidEagerSingletons.initEagerSingletons(applicationComponent);
+	}
+
+	public AndroidComponent getApplicationComponent() {
+		return applicationComponent;
+	}
+}
diff --git a/briar-android/test/java/briarproject/activity/TestSetupActivity.java b/briar-android/test/java/briarproject/activity/TestSetupActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..923372a494b72a011757be7602cd457750b1d18a
--- /dev/null
+++ b/briar-android/test/java/briarproject/activity/TestSetupActivity.java
@@ -0,0 +1,20 @@
+package briarproject.activity;
+
+import org.briarproject.android.SetupActivity;
+import org.briarproject.android.controller.SetupController;
+
+/**
+ * This class exposes the SetupController and offers the possibility to
+ * override it.
+ */
+public class TestSetupActivity extends SetupActivity {
+
+	public SetupController getController() {
+		return this.setupController;
+	}
+
+	public void setController(SetupController setupController) {
+		this.setupController = setupController;
+	}
+
+}
diff --git a/briar-core/src/org/briarproject/introduction/IntroductionModule.java b/briar-core/src/org/briarproject/introduction/IntroductionModule.java
index 9e51aca734a7bec5c1317e413593cf2285861b45..4ea0ac6c3b5a9251d6b41db231f01f02cc3409fe 100644
--- a/briar-core/src/org/briarproject/introduction/IntroductionModule.java
+++ b/briar-core/src/org/briarproject/introduction/IntroductionModule.java
@@ -26,7 +26,7 @@ public class IntroductionModule {
 
 	@Provides
 	@Singleton
-	MessageValidator getValidator(MessageQueueManager messageQueueManager,
+	MessageValidator provideValidator(MessageQueueManager messageQueueManager,
 			IntroductionManager introductionManager,
 			MetadataEncoder metadataEncoder, ClientHelper clientHelper,
 			Clock clock) {
@@ -43,7 +43,7 @@ public class IntroductionModule {
 
 	@Provides
 	@Singleton
-	IntroductionManager getIntroductionManager(
+	IntroductionManager provideIntroductionManager(
 			LifecycleManager lifecycleManager,
 			ContactManager contactManager,
 			MessageQueueManager messageQueueManager,
diff --git a/briar-core/src/org/briarproject/system/LinuxSeedProvider.java b/briar-core/src/org/briarproject/system/LinuxSeedProvider.java
index 58b22d32adc29c43285a7c27aa6ce395b2e8af5d..6481b4a5f2f3d8eec0d2e8357898eeab7dc45713 100644
--- a/briar-core/src/org/briarproject/system/LinuxSeedProvider.java
+++ b/briar-core/src/org/briarproject/system/LinuxSeedProvider.java
@@ -1,6 +1,6 @@
 package org.briarproject.system;
 
-import static java.util.logging.Level.WARNING;
+import org.briarproject.api.system.SeedProvider;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -13,7 +13,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.logging.Logger;
 
-import org.briarproject.api.system.SeedProvider;
+import static java.util.logging.Level.WARNING;
 
 class LinuxSeedProvider implements SeedProvider {