diff --git a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java
index e19f2305f25f5a31eebc9f77e37c77e1643ae11a..1ce36ed39f5aa82ebf35cace6f63d15cfdb2452d 100644
--- a/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java
+++ b/bramble-android/src/main/java/org/briarproject/bramble/account/AndroidAccountManager.java
@@ -69,12 +69,16 @@ class AndroidAccountManager extends AccountManagerImpl
 	public void deleteAccount() {
 		synchronized (stateChangeLock) {
 			super.deleteAccount();
-			SharedPreferences defaultPrefs =
-					PreferenceManager.getDefaultSharedPreferences(appContext);
+			SharedPreferences defaultPrefs = getDefaultSharedPreferences();
 			deleteAppData(prefs, defaultPrefs);
 		}
 	}
 
+	// Package access for testing
+	SharedPreferences getDefaultSharedPreferences() {
+		return PreferenceManager.getDefaultSharedPreferences(appContext);
+	}
+
 	// Locking: stateChangeLock
 	private void deleteAppData(SharedPreferences... clear) {
 		// Clear and commit shared preferences
diff --git a/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java
index 1922954a072e297bcf9d5f91e7bc0695b52a0704..d283adceac17a91796dccef1efe47793ebe2c34f 100644
--- a/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java
+++ b/bramble-android/src/test/java/org/briarproject/bramble/account/AndroidAccountManagerTest.java
@@ -2,6 +2,7 @@ package org.briarproject.bramble.account;
 
 import android.app.Application;
 import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
 
 import org.briarproject.bramble.api.crypto.CryptoComponent;
 import org.briarproject.bramble.api.db.DatabaseConfig;
@@ -25,37 +26,50 @@ import static org.briarproject.bramble.util.StringUtils.toHexString;
 public class AndroidAccountManagerTest extends BrambleMockTestCase {
 
 	private final SharedPreferences prefs =
-			context.mock(SharedPreferences.class);
+			context.mock(SharedPreferences.class, "prefs");
+	private final SharedPreferences defaultPrefs =
+			context.mock(SharedPreferences.class, "defaultPrefs");
 	private final DatabaseConfig databaseConfig =
 			context.mock(DatabaseConfig.class);
 	private final CryptoComponent crypto = context.mock(CryptoComponent.class);
 	private final SharedPreferences.Editor
 			editor = context.mock(SharedPreferences.Editor.class);
 	private final Application app;
+	private final ApplicationInfo applicationInfo;
 
 	private final String encryptedKeyHex = toHexString(getRandomBytes(123));
 	private final File testDir = getTestDirectory();
 	private final File keyDir = new File(testDir, "key");
 	private final File keyFile = new File(keyDir, "db.key");
 	private final File keyBackupFile = new File(keyDir, "db.key.bak");
+	private final File dbDir = new File(testDir, "db");
 
 	private AndroidAccountManager accountManager;
 
 	public AndroidAccountManagerTest() {
 		context.setImposteriser(ClassImposteriser.INSTANCE);
 		app = context.mock(Application.class);
+		applicationInfo = new ApplicationInfo();
+		applicationInfo.dataDir = testDir.getAbsolutePath();
 	}
 
 	@Before
 	public void setUp() {
 		context.checking(new Expectations() {{
+			allowing(databaseConfig).getDatabaseDirectory();
+			will(returnValue(dbDir));
 			allowing(databaseConfig).getDatabaseKeyDirectory();
 			will(returnValue(keyDir));
 			allowing(app).getApplicationContext();
 			will(returnValue(app));
 		}});
 		accountManager = new AndroidAccountManager(databaseConfig, crypto,
-				prefs, app);
+				prefs, app) {
+			@Override
+			SharedPreferences getDefaultSharedPreferences() {
+				return defaultPrefs;
+			}
+		};
 	}
 
 	@Test
@@ -74,12 +88,70 @@ public class AndroidAccountManagerTest extends BrambleMockTestCase {
 		assertFalse(keyFile.exists());
 		assertFalse(keyBackupFile.exists());
 
-		assertEquals(encryptedKeyHex, accountManager.loadEncryptedDatabaseKey());
+		assertEquals(encryptedKeyHex,
+				accountManager.loadEncryptedDatabaseKey());
 
 		assertTrue(keyFile.exists());
 		assertTrue(keyBackupFile.exists());
 	}
 
+	@Test
+	public void testDeleteAccountClearsSharedPrefsAndDeletesFiles()
+			throws Exception {
+		// Directories 'lib' and 'shared_prefs' should be spared
+		File libDir = new File(testDir, "lib");
+		File libFile = new File(libDir, "file");
+		File sharedPrefsDir = new File(testDir, "shared_prefs");
+		File sharedPrefsFile = new File(sharedPrefsDir, "file");
+		// Directory 'cache' should be emptied
+		File cacheDir = new File(testDir, "cache");
+		File cacheFile = new File(cacheDir, "file");
+		// Other directories should be deleted
+		File potatoDir = new File(testDir, ".potato");
+		File potatoFile = new File(potatoDir, "file");
+
+		context.checking(new Expectations() {{
+			oneOf(prefs).edit();
+			will(returnValue(editor));
+			oneOf(editor).clear();
+			will(returnValue(editor));
+			oneOf(editor).commit();
+			will(returnValue(true));
+			oneOf(defaultPrefs).edit();
+			will(returnValue(editor));
+			oneOf(editor).clear();
+			will(returnValue(editor));
+			oneOf(editor).commit();
+			will(returnValue(true));
+			oneOf(app).getApplicationInfo();
+			will(returnValue(applicationInfo));
+		}});
+
+		assertTrue(dbDir.mkdirs());
+		assertTrue(keyDir.mkdirs());
+		assertTrue(libDir.mkdirs());
+		assertTrue(libFile.createNewFile());
+		assertTrue(sharedPrefsDir.mkdirs());
+		assertTrue(sharedPrefsFile.createNewFile());
+		assertTrue(cacheDir.mkdirs());
+		assertTrue(cacheFile.createNewFile());
+		assertTrue(potatoDir.mkdirs());
+		assertTrue(potatoFile.createNewFile());
+
+		accountManager.deleteAccount();
+
+		assertFalse(dbDir.exists());
+		assertFalse(keyDir.exists());
+		assertTrue(libDir.exists());
+		assertTrue(libFile.exists());
+		assertTrue(sharedPrefsDir.exists());
+		assertTrue(sharedPrefsFile.exists());
+		assertTrue(cacheDir.exists());
+		assertFalse(cacheFile.exists());
+		assertFalse(potatoDir.exists());
+		assertFalse(potatoFile.exists());
+	}
+
 	@After
 	public void tearDown() {
 		deleteTestDirectory(testDir);
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java
index e2784c145815baaa818a64bc2e1997f36783c216..5b475ae6362bf098b390c43971e0585cca392c15 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/account/AccountManager.java
@@ -12,7 +12,7 @@ public interface AccountManager {
 	 * Returns true if the manager has the database key. This will be false
 	 * before {@link #createAccount(String)} or {@link #signIn(String)} has
 	 * been called, and true after {@link #createAccount(String)} or
-	 * {@link #signIn(String)} has returned, until the process exits.
+	 * {@link #signIn(String)} has returned true, until the process exits.
 	 */
 	boolean hasDatabaseKey();
 
@@ -20,14 +20,14 @@ public interface AccountManager {
 	 * Returns the database key if the manager has it. This will be null
 	 * before {@link #createAccount(String)} or {@link #signIn(String)} has
 	 * been called, and non-null after {@link #createAccount(String)} or
-	 * {@link #signIn(String)} has returned, until the process exits.
+	 * {@link #signIn(String)} has returned true, until the process exits.
 	 */
 	@Nullable
 	SecretKey getDatabaseKey();
 
 	/**
-	 * Returns true if the encrypted database key can be loaded from disk and
-	 * the database directory exists.
+	 * Returns true if the encrypted database key can be loaded from disk, and
+	 * the database directory exists and is a directory.
 	 */
 	boolean accountExists();
 
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java
index 6e43e23f8f09d2da85333a4f6c154a2bcf88471d..998fa1c5e4ccc84fda13f9446e200454cc9f3e99 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/account/AccountManagerImplTest.java
@@ -1,6 +1,7 @@
 package org.briarproject.bramble.account;
 
 import org.briarproject.bramble.api.crypto.CryptoComponent;
+import org.briarproject.bramble.api.crypto.SecretKey;
 import org.briarproject.bramble.api.db.DatabaseConfig;
 import org.briarproject.bramble.test.BrambleMockTestCase;
 import org.jmock.Expectations;
@@ -22,9 +23,12 @@ import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
 import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
+import static org.briarproject.bramble.test.TestUtils.getSecretKey;
 import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
 import static org.briarproject.bramble.util.StringUtils.toHexString;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 public class AccountManagerImplTest extends BrambleMockTestCase {
 
@@ -32,10 +36,15 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
 			context.mock(DatabaseConfig.class);
 	private final CryptoComponent crypto = context.mock(CryptoComponent.class);
 
+	private final SecretKey key = getSecretKey();
 	private final byte[] encryptedKey = getRandomBytes(123);
 	private final String encryptedKeyHex = toHexString(encryptedKey);
-	private final String oldEncryptedKeyHex = toHexString(getRandomBytes(123));
+	private final byte[] newEncryptedKey = getRandomBytes(123);
+	private final String newEncryptedKeyHex = toHexString(newEncryptedKey);
+	private final String password = "some.password";
+	private final String newPassword = "some.new.password";
 	private final File testDir = getTestDirectory();
+	private final File dbDir = new File(testDir, "db");
 	private final File keyDir = new File(testDir, "key");
 	private final File keyFile = new File(keyDir, "db.key");
 	private final File keyBackupFile = new File(keyDir, "db.key.bak");
@@ -45,56 +54,115 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
 	@Before
 	public void setUp() {
 		context.checking(new Expectations() {{
+			allowing(databaseConfig).getDatabaseDirectory();
+			will(returnValue(dbDir));
 			allowing(databaseConfig).getDatabaseKeyDirectory();
 			will(returnValue(keyDir));
 		}});
-		assertTrue(keyDir.mkdirs());
+
 		accountManager = new AccountManagerImpl(databaseConfig, crypto);
+
+		assertFalse(keyFile.exists());
+		assertFalse(keyBackupFile.exists());
 	}
 
 	@Test
-	public void testDbKeyIsLoadedFromPrimaryFile() throws Exception {
+	public void testCreatingAccountStoresDbKey() throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(crypto).generateSecretKey();
+			will(returnValue(key));
+			oneOf(crypto).encryptWithPassword(key.getBytes(), password);
+			will(returnValue(encryptedKey));
+		}});
+
+		accountManager.createAccount(password);
+
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+	}
+
+	@Test
+	public void testSignInReturnsFalseIfDbKeyCannotBeLoaded() {
+		assertFalse(accountManager.signIn(password));
+		assertFalse(accountManager.hasDatabaseKey());
+
 		assertFalse(keyFile.exists());
 		assertFalse(keyBackupFile.exists());
+	}
+
+	@Test
+	public void testSignInReturnsFalseIfPasswordIsWrong() throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(crypto).decryptWithPassword(encryptedKey, password);
+			will(returnValue(null));
+		}});
 
 		storeDatabaseKey(keyFile, encryptedKeyHex);
+		storeDatabaseKey(keyBackupFile, encryptedKeyHex);
 
-		assertTrue(keyFile.exists());
-		assertFalse(keyBackupFile.exists());
 		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+
+		assertFalse(accountManager.signIn(password));
+		assertFalse(accountManager.hasDatabaseKey());
+
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+	}
+
+	@Test
+	public void testSignInReturnsTrueIfPasswordIsRight() throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(crypto).decryptWithPassword(encryptedKey, password);
+			will(returnValue(key.getBytes()));
+		}});
+
+		storeDatabaseKey(keyFile, encryptedKeyHex);
+		storeDatabaseKey(keyBackupFile, encryptedKeyHex);
+
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+
+		assertTrue(accountManager.signIn(password));
+		assertTrue(accountManager.hasDatabaseKey());
+		SecretKey decrypted = accountManager.getDatabaseKey();
+		assertNotNull(decrypted);
+		assertArrayEquals(key.getBytes(), decrypted.getBytes());
+
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+	}
+
+	@Test
+	public void testDbKeyIsLoadedFromPrimaryFile() throws Exception {
+		storeDatabaseKey(keyFile, encryptedKeyHex);
+
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertFalse(keyBackupFile.exists());
 
 		assertEquals(encryptedKeyHex,
 				accountManager.loadEncryptedDatabaseKey());
 
-		assertTrue(keyFile.exists());
-		assertFalse(keyBackupFile.exists());
 		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertFalse(keyBackupFile.exists());
 	}
 
 	@Test
 	public void testDbKeyIsLoadedFromBackupFile() throws Exception {
-		assertFalse(keyFile.exists());
-		assertFalse(keyBackupFile.exists());
-
 		storeDatabaseKey(keyBackupFile, encryptedKeyHex);
 
 		assertFalse(keyFile.exists());
-		assertTrue(keyBackupFile.exists());
 		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
 
 		assertEquals(encryptedKeyHex,
 				accountManager.loadEncryptedDatabaseKey());
 
 		assertFalse(keyFile.exists());
-		assertTrue(keyBackupFile.exists());
 		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
 	}
 
 	@Test
 	public void testDbKeyIsNullIfNotFound() {
-		assertFalse(keyFile.exists());
-		assertFalse(keyBackupFile.exists());
-
 		assertNull(accountManager.loadEncryptedDatabaseKey());
 
 		assertFalse(keyFile.exists());
@@ -103,43 +171,156 @@ public class AccountManagerImplTest extends BrambleMockTestCase {
 
 	@Test
 	public void testStoringDbKeyOverwritesPrimary() throws Exception {
-		assertFalse(keyFile.exists());
+		storeDatabaseKey(keyFile, encryptedKeyHex);
+
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
 		assertFalse(keyBackupFile.exists());
 
-		storeDatabaseKey(keyFile, oldEncryptedKeyHex);
+		assertTrue(accountManager.storeEncryptedDatabaseKey(
+				newEncryptedKeyHex));
+
+		assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
+	}
 
-		assertTrue(keyFile.exists());
+	@Test
+	public void testStoringDbKeyOverwritesBackup() throws Exception {
+		storeDatabaseKey(keyBackupFile, encryptedKeyHex);
+
+		assertFalse(keyFile.exists());
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+
+		assertTrue(accountManager.storeEncryptedDatabaseKey(
+				newEncryptedKeyHex));
+
+		assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
+	}
+
+	@Test
+	public void testAccountExistsReturnsFalseIfDbKeyCannotBeLoaded() {
+		assertFalse(accountManager.accountExists());
+
+		assertFalse(keyFile.exists());
 		assertFalse(keyBackupFile.exists());
-		assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyFile));
+	}
+
+	@Test
+	public void testAccountExistsReturnsFalseIfDbDirectoryDoesNotExist()
+			throws Exception {
+		storeDatabaseKey(keyFile, encryptedKeyHex);
+		storeDatabaseKey(keyBackupFile, encryptedKeyHex);
 
-		assertTrue(accountManager.storeEncryptedDatabaseKey(encryptedKeyHex));
+		assertFalse(dbDir.exists());
+
+		assertFalse(accountManager.accountExists());
 
-		assertTrue(keyFile.exists());
-		assertTrue(keyBackupFile.exists());
 		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
 		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+		assertFalse(dbDir.exists());
 	}
 
 	@Test
-	public void testStoringDbKeyOverwritesBackup() throws Exception {
+	public void testAccountExistsReturnsFalseIfDbDirectoryIsNotDirectory()
+			throws Exception {
+		storeDatabaseKey(keyFile, encryptedKeyHex);
+		storeDatabaseKey(keyBackupFile, encryptedKeyHex);
+
+		assertTrue(dbDir.createNewFile());
+		assertFalse(dbDir.isDirectory());
+
+		assertFalse(accountManager.accountExists());
+
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+		assertTrue(dbDir.exists());
+		assertFalse(dbDir.isDirectory());
+	}
+
+	@Test
+	public void testAccountExistsReturnsTrueIfDbDirectoryIsDirectory()
+			throws Exception {
+		storeDatabaseKey(keyFile, encryptedKeyHex);
+		storeDatabaseKey(keyBackupFile, encryptedKeyHex);
+
+		assertTrue(dbDir.mkdirs());
+		assertTrue(dbDir.isDirectory());
+
+		assertTrue(accountManager.accountExists());
+
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+		assertTrue(dbDir.exists());
+		assertTrue(dbDir.isDirectory());
+	}
+
+	@Test
+	public void testCreateAccountStoresDbKey() throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(crypto).generateSecretKey();
+			will(returnValue(key));
+			oneOf(crypto).encryptWithPassword(key.getBytes(), password);
+			will(returnValue(encryptedKey));
+		}});
+
+		assertFalse(accountManager.hasDatabaseKey());
+
+		assertTrue(accountManager.createAccount(password));
+
+		assertTrue(accountManager.hasDatabaseKey());
+		SecretKey dbKey = accountManager.getDatabaseKey();
+		assertNotNull(dbKey);
+		assertArrayEquals(key.getBytes(), dbKey.getBytes());
+
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
+	}
+
+	@Test
+	public void testChangePasswordReturnsFalseIfDbKeyCannotBeLoaded() {
+		assertFalse(accountManager.changePassword(password, newPassword));
+
 		assertFalse(keyFile.exists());
 		assertFalse(keyBackupFile.exists());
+	}
 
-		storeDatabaseKey(keyBackupFile, oldEncryptedKeyHex);
+	@Test
+	public void testChangePasswordReturnsFalseIfPasswordIsWrong()
+			throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(crypto).decryptWithPassword(encryptedKey, password);
+			will(returnValue(null));
+		}});
 
-		assertFalse(keyFile.exists());
-		assertTrue(keyBackupFile.exists());
-		assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
+		storeDatabaseKey(keyFile, encryptedKeyHex);
+		storeDatabaseKey(keyBackupFile, encryptedKeyHex);
 
-		assertTrue(accountManager.storeEncryptedDatabaseKey(encryptedKeyHex));
+		assertFalse(accountManager.changePassword(password, newPassword));
 
-		assertTrue(keyFile.exists());
-		assertTrue(keyBackupFile.exists());
 		assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
 		assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
 	}
 
+	@Test
+	public void testChangePasswordReturnsTrueIfPasswordIsRight() throws Exception {
+		context.checking(new Expectations() {{
+			oneOf(crypto).decryptWithPassword(encryptedKey, password);
+			will(returnValue(key.getBytes()));
+			oneOf(crypto).encryptWithPassword(key.getBytes(), newPassword);
+			will(returnValue(newEncryptedKey));
+		}});
+
+		storeDatabaseKey(keyFile, encryptedKeyHex);
+		storeDatabaseKey(keyBackupFile, encryptedKeyHex);
+
+		assertTrue(accountManager.changePassword(password, newPassword));
+
+		assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyFile));
+		assertEquals(newEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
+	}
+
 	private void storeDatabaseKey(File f, String hex) throws IOException {
+		f.getParentFile().mkdirs();
 		FileOutputStream out = new FileOutputStream(f);
 		out.write(hex.getBytes("UTF-8"));
 		out.flush();