Move account deletion into AccountManager.

This commit is contained in:
akwizgran
2018-07-26 17:13:08 +01:00
parent 233af69909
commit 1edf2bfa75
20 changed files with 252 additions and 168 deletions

View File

@@ -21,6 +21,7 @@
<method>
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-api" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-core" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-android" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in bramble-j2se" run_configuration_type="AndroidJUnit" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="All tests in briar-core" run_configuration_type="AndroidJUnit" />
</method>

View File

@@ -34,6 +34,14 @@ dependencies {
compileOnly 'javax.annotation:jsr250-api:1.0'
testImplementation project(path: ':bramble-api', configuration: 'testOutput')
testImplementation 'junit:junit:4.12'
testImplementation "org.jmock:jmock:2.8.2"
testImplementation "org.jmock:jmock-junit4:2.8.2"
testImplementation "org.jmock:jmock-legacy:2.8.2"
testImplementation "org.hamcrest:hamcrest-library:1.3"
testImplementation "org.hamcrest:hamcrest-core:1.3"
androidTestImplementation project(path: ':bramble-api', configuration: 'testOutput')
androidTestImplementation project(path: ':bramble-core', configuration: 'testOutput')
androidTestImplementation 'com.android.support.test:runner:1.0.2'

View File

@@ -2,6 +2,7 @@ package org.briarproject.bramble;
import android.app.Application;
import org.briarproject.bramble.account.AndroidAccountModule;
import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.plugin.tor.CircumventionProviderImpl;
import org.briarproject.bramble.system.AndroidSystemModule;
@@ -12,6 +13,7 @@ import dagger.Module;
import dagger.Provides;
@Module(includes = {
AndroidAccountModule.class,
AndroidSystemModule.class
})
public class BrambleAndroidModule {

View File

@@ -0,0 +1,96 @@
package org.briarproject.bramble.account;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.util.IoUtils;
import java.io.File;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
class AndroidAccountManager extends AccountManagerImpl
implements AccountManager {
private static final Logger LOG =
Logger.getLogger(AndroidAccountManager.class.getName());
private static final String PREF_DB_KEY = "key";
private final SharedPreferences briarPrefs;
private final Context appContext;
@Inject
AndroidAccountManager(DatabaseConfig databaseConfig,
SharedPreferences briarPrefs, Application app) {
super(databaseConfig);
this.briarPrefs = briarPrefs;
appContext = app.getApplicationContext();
}
@Override
@Nullable
public String getEncryptedDatabaseKey() {
String key = getDatabaseKeyFromPreferences();
if (key == null) key = super.getEncryptedDatabaseKey();
else migrateDatabaseKeyToFile(key);
return key;
}
@Nullable
private String getDatabaseKeyFromPreferences() {
String key = briarPrefs.getString(PREF_DB_KEY, null);
if (key == null) LOG.info("No database key in preferences");
else LOG.info("Found database key in preferences");
return key;
}
private void migrateDatabaseKeyToFile(String key) {
if (storeEncryptedDatabaseKey(key)) {
if (briarPrefs.edit().remove(PREF_DB_KEY).commit())
LOG.info("Database key migrated to file");
else LOG.warning("Database key not removed from preferences");
} else {
LOG.warning("Database key not migrated to file");
}
}
@Override
public void deleteAccount() {
super.deleteAccount();
SharedPreferences defaultPrefs =
PreferenceManager.getDefaultSharedPreferences(appContext);
deleteAppData(briarPrefs, defaultPrefs);
}
private void deleteAppData(SharedPreferences... clear) {
// Clear and commit shared preferences
for (SharedPreferences prefs : clear) {
if (!prefs.edit().clear().commit())
LOG.warning("Could not clear shared preferences");
}
// Delete files, except lib and shared_prefs directories
File dataDir = new File(appContext.getApplicationInfo().dataDir);
File[] children = dataDir.listFiles();
if (children == null) {
LOG.warning("Could not list files in app data dir");
} else {
for (File child : children) {
String name = child.getName();
if (!name.equals("lib") && !name.equals("shared_prefs")) {
IoUtils.deleteFileOrDir(child);
}
}
}
// Recreate the cache dir as some OpenGL drivers expect it to exist
if (!new File(dataDir, "cache").mkdir())
LOG.warning("Could not recreate cache dir");
}
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.bramble.account;
import org.briarproject.bramble.api.account.AccountManager;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidAccountModule {
@Provides
@Singleton
AccountManager provideAccountManager(AndroidAccountManager accountManager) {
return accountManager;
}
}

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.provider.Settings;
@@ -58,30 +57,6 @@ public class AndroidUtils {
&& !address.equals(FAKE_BLUETOOTH_ADDRESS);
}
public static void deleteAppData(Context ctx, SharedPreferences... clear) {
// Clear and commit shared preferences
for (SharedPreferences prefs : clear) {
if (!prefs.edit().clear().commit())
LOG.warning("Could not clear shared preferences");
}
// Delete files, except lib and shared_prefs directories
File dataDir = new File(ctx.getApplicationInfo().dataDir);
File[] children = dataDir.listFiles();
if (children == null) {
LOG.warning("Could not list files in app data dir");
} else {
for (File child : children) {
String name = child.getName();
if (!name.equals("lib") && !name.equals("shared_prefs")) {
IoUtils.deleteFileOrDir(child);
}
}
}
// Recreate the cache dir as some OpenGL drivers expect it to exist
if (!new File(dataDir, "cache").mkdir())
LOG.warning("Could not recreate cache dir");
}
public static File getReportDir(Context ctx) {
return ctx.getDir(STORED_REPORTS, MODE_PRIVATE);
}

View File

@@ -0,0 +1,84 @@
package org.briarproject.bramble.account;
import android.app.Application;
import android.content.SharedPreferences;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.jmock.Expectations;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
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.getTestDirectory;
import static org.briarproject.bramble.util.StringUtils.toHexString;
public class AndroidAccountManagerTest extends BrambleMockTestCase {
private final SharedPreferences prefs =
context.mock(SharedPreferences.class);
private final DatabaseConfig databaseConfig =
context.mock(DatabaseConfig.class);
private final SharedPreferences.Editor
editor = context.mock(SharedPreferences.Editor.class);
private final Application app;
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 AndroidAccountManager accountManager;
public AndroidAccountManagerTest() {
context.setImposteriser(ClassImposteriser.INSTANCE);
app = context.mock(Application.class);
}
@Before
public void setUp() {
context.checking(new Expectations() {{
allowing(databaseConfig).getDatabaseKeyDirectory();
will(returnValue(keyDir));
allowing(app).getApplicationContext();
will(returnValue(app));
}});
accountManager = new AndroidAccountManager(databaseConfig, prefs, app);
}
@Test
public void testDbKeyIsMigratedFromPreferencesToFile() {
context.checking(new Expectations() {{
oneOf(prefs).getString("key", null);
will(returnValue(encryptedKeyHex));
oneOf(prefs).edit();
will(returnValue(editor));
oneOf(editor).remove("key");
will(returnValue(editor));
oneOf(editor).commit();
will(returnValue(true));
}});
assertFalse(keyFile.exists());
assertFalse(keyBackupFile.exists());
assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey());
assertTrue(keyFile.exists());
assertTrue(keyBackupFile.exists());
}
@After
public void tearDown() {
deleteTestDirectory(testDir);
}
}

View File

@@ -19,4 +19,8 @@ public interface AccountManager {
String getEncryptedDatabaseKey();
boolean storeEncryptedDatabaseKey(String hex);
boolean accountExists();
void deleteAccount();
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble;
import org.briarproject.bramble.account.AccountModule;
import org.briarproject.bramble.client.ClientModule;
import org.briarproject.bramble.contact.ContactModule;
import org.briarproject.bramble.crypto.CryptoExecutorModule;
@@ -27,7 +26,6 @@ import org.briarproject.bramble.versioning.VersioningModule;
import dagger.Module;
@Module(includes = {
AccountModule.class,
ClientModule.class,
ContactModule.class,
CryptoModule.class,

View File

@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.util.IoUtils;
import java.io.BufferedReader;
import java.io.File;
@@ -137,4 +138,17 @@ class AccountManagerImpl implements AccountManager {
out.flush();
out.close();
}
@Override
public boolean accountExists() {
return getEncryptedDatabaseKey() != null
&& databaseConfig.getDatabaseDirectory().isDirectory();
}
@Override
public void deleteAccount() {
LOG.info("Deleting account");
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseKeyDirectory());
IoUtils.deleteFileOrDir(databaseConfig.getDatabaseDirectory());
}
}

View File

@@ -1,7 +1,5 @@
package org.briarproject.briar.android.controller;
import android.content.Context;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.Nullable;
@@ -14,7 +12,7 @@ public interface ConfigController {
boolean storeEncryptedDatabaseKey(String hex);
void deleteAccount(Context ctx);
void deleteAccount();
boolean accountExists();

View File

@@ -1,64 +1,32 @@
package org.briarproject.briar.android.controller;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.v7.preference.PreferenceManager;
import android.util.Log;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.AndroidUtils;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
// TODO: Remove this class, which just delegates to AccountManager
@NotNullByDefault
public class ConfigControllerImpl implements ConfigController {
private static final Logger LOG =
Logger.getLogger(ConfigControllerImpl.class.getName());
private static final String PREF_DB_KEY = "key";
private final SharedPreferences briarPrefs;
protected final AccountManager accountManager;
protected final DatabaseConfig databaseConfig;
@Inject
public ConfigControllerImpl(SharedPreferences briarPrefs,
AccountManager accountManager, DatabaseConfig databaseConfig) {
this.briarPrefs = briarPrefs;
public ConfigControllerImpl(AccountManager accountManager) {
// TODO: Remove
Log.i(getClass().getName(), "Using account manager "
+ accountManager.getClass().getName());
this.accountManager = accountManager;
this.databaseConfig = databaseConfig;
}
@Override
@Nullable
public String getEncryptedDatabaseKey() {
String key = getDatabaseKeyFromPreferences();
if (key == null) key = accountManager.getEncryptedDatabaseKey();
else migrateDatabaseKeyToFile(key);
return key;
}
@Nullable
private String getDatabaseKeyFromPreferences() {
String key = briarPrefs.getString(PREF_DB_KEY, null);
if (key == null) LOG.info("No database key in preferences");
else LOG.info("Found database key in preferences");
return key;
}
private void migrateDatabaseKeyToFile(String key) {
if (accountManager.storeEncryptedDatabaseKey(key)) {
if (briarPrefs.edit().remove(PREF_DB_KEY).commit())
LOG.info("Database key migrated to file");
else LOG.warning("Database key not removed from preferences");
} else {
LOG.warning("Database key not migrated to file");
}
return accountManager.getEncryptedDatabaseKey();
}
@Override
@@ -67,17 +35,13 @@ public class ConfigControllerImpl implements ConfigController {
}
@Override
public void deleteAccount(Context ctx) {
LOG.info("Deleting account");
SharedPreferences defaultPrefs =
PreferenceManager.getDefaultSharedPreferences(ctx);
AndroidUtils.deleteAppData(ctx, briarPrefs, defaultPrefs);
public void deleteAccount() {
accountManager.deleteAccount();
}
@Override
public boolean accountExists() {
return getEncryptedDatabaseKey() != null &&
databaseConfig.getDatabaseDirectory().isDirectory();
return accountManager.hasDatabaseKey();
}
@Override

View File

@@ -105,7 +105,7 @@ public class PasswordActivity extends BaseActivity {
}
private void deleteAccount() {
passwordController.deleteAccount(this);
passwordController.deleteAccount();
Localizer.reinitialize();
UiUtils.setTheme(this, getString(R.string.pref_theme_light_value));
setResult(RESULT_CANCELED);

View File

@@ -1,13 +1,10 @@
package org.briarproject.briar.android.login;
import android.content.SharedPreferences;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.android.controller.ConfigControllerImpl;
@@ -33,11 +30,10 @@ public class PasswordControllerImpl extends ConfigControllerImpl
private final PasswordStrengthEstimator strengthEstimator;
@Inject
PasswordControllerImpl(SharedPreferences briarPrefs,
AccountManager accountManager, DatabaseConfig databaseConfig,
PasswordControllerImpl(AccountManager accountManager,
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
PasswordStrengthEstimator strengthEstimator) {
super(briarPrefs, accountManager, databaseConfig);
super(accountManager);
this.cryptoExecutor = cryptoExecutor;
this.crypto = crypto;
this.strengthEstimator = strengthEstimator;

View File

@@ -1,6 +1,5 @@
package org.briarproject.briar.android.login;
import android.content.SharedPreferences;
import android.support.annotation.Nullable;
import org.briarproject.bramble.api.account.AccountManager;
@@ -8,7 +7,6 @@ import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -33,13 +31,11 @@ public class SetupControllerImpl extends PasswordControllerImpl
private volatile SetupActivity setupActivity;
@Inject
SetupControllerImpl(SharedPreferences briarPrefs,
AccountManager accountManager, DatabaseConfig databaseConfig,
SetupControllerImpl(AccountManager accountManager,
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
PasswordStrengthEstimator strengthEstimator,
IdentityManager identityManager) {
super(briarPrefs, accountManager, databaseConfig, cryptoExecutor,
crypto, strengthEstimator);
super(accountManager, cryptoExecutor, crypto, strengthEstimator);
this.identityManager = identityManager;
}

View File

@@ -94,7 +94,7 @@ public class PanicResponderActivity extends BriarActivity {
private void deleteAllData() {
androidExecutor.runOnBackgroundThread(() -> {
configController.deleteAccount(PanicResponderActivity.this);
configController.deleteAccount();
// TODO somehow delete/shred the database more thoroughly
PanicResponder.deleteAllAppData(PanicResponderActivity.this);

View File

@@ -69,7 +69,7 @@ public class SplashScreenActivity extends BaseActivity {
startActivity(new Intent(this, OpenDatabaseActivity.class));
} else {
LOG.info("Account does not exist");
configController.deleteAccount(this);
configController.deleteAccount();
startActivity(new Intent(this, SetupActivity.class));
}
}

View File

@@ -1,49 +0,0 @@
package org.briarproject.briar.android.controller;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.jmock.Expectations;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.util.StringUtils.toHexString;
public class ConfigControllerImplTest extends BrambleMockTestCase {
private final SharedPreferences prefs =
context.mock(SharedPreferences.class);
private final AccountManager accountManager =
context.mock(AccountManager.class);
private final DatabaseConfig databaseConfig =
context.mock(DatabaseConfig.class);
private final Editor editor = context.mock(Editor.class);
private final String encryptedKeyHex = toHexString(getRandomBytes(123));
@Test
public void testDbKeyIsMigratedFromPreferencesToFile() {
context.checking(new Expectations() {{
oneOf(prefs).getString("key", null);
will(returnValue(encryptedKeyHex));
oneOf(accountManager).storeEncryptedDatabaseKey(encryptedKeyHex);
will(returnValue(true));
oneOf(prefs).edit();
will(returnValue(editor));
oneOf(editor).remove("key");
will(returnValue(editor));
oneOf(editor).commit();
will(returnValue(true));
}});
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
databaseConfig);
assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey());
}
}

View File

@@ -1,11 +1,8 @@
package org.briarproject.briar.android.login;
import android.content.SharedPreferences;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.ImmediateExecutor;
import org.jmock.Expectations;
@@ -22,12 +19,8 @@ import static org.briarproject.bramble.util.StringUtils.toHexString;
public class PasswordControllerImplTest extends BrambleMockTestCase {
private final SharedPreferences briarPrefs =
context.mock(SharedPreferences.class);
private final AccountManager accountManager =
context.mock(AccountManager.class);
private final DatabaseConfig databaseConfig =
context.mock(DatabaseConfig.class);
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
private final PasswordStrengthEstimator estimator =
context.mock(PasswordStrengthEstimator.class);
@@ -46,8 +39,6 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
public void testChangePasswordReturnsTrue() {
context.checking(new Expectations() {{
// Look up the encrypted DB key
oneOf(briarPrefs).getString("key", null);
will(returnValue(null));
oneOf(accountManager).getEncryptedDatabaseKey();
will(returnValue(oldEncryptedKeyHex));
// Decrypt and re-encrypt the key
@@ -60,9 +51,8 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
will(returnValue(true));
}});
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
accountManager, databaseConfig, cryptoExecutor, crypto,
estimator);
PasswordControllerImpl p = new PasswordControllerImpl(accountManager,
cryptoExecutor, crypto, estimator);
AtomicBoolean capturedResult = new AtomicBoolean(false);
p.changePassword(oldPassword, newPassword, capturedResult::set);
@@ -73,8 +63,6 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
public void testChangePasswordReturnsFalseIfOldPasswordIsWrong() {
context.checking(new Expectations() {{
// Look up the encrypted DB key
oneOf(briarPrefs).getString("key", null);
will(returnValue(null));
oneOf(accountManager).getEncryptedDatabaseKey();
will(returnValue(oldEncryptedKeyHex));
// Try to decrypt the key - the password is wrong
@@ -82,9 +70,8 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
will(returnValue(null));
}});
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
accountManager, databaseConfig, cryptoExecutor, crypto,
estimator);
PasswordControllerImpl p = new PasswordControllerImpl(accountManager,
cryptoExecutor, crypto, estimator);
AtomicBoolean capturedResult = new AtomicBoolean(true);
p.changePassword(oldPassword, newPassword, capturedResult::set);

View File

@@ -1,12 +1,9 @@
package org.briarproject.briar.android.login;
import android.content.SharedPreferences;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.test.BrambleMockTestCase;
@@ -28,12 +25,8 @@ import static org.briarproject.bramble.util.StringUtils.toHexString;
public class SetupControllerImplTest extends BrambleMockTestCase {
private final SharedPreferences briarPrefs =
context.mock(SharedPreferences.class);
private final AccountManager accountManager =
context.mock(AccountManager.class);
private final DatabaseConfig databaseConfig =
context.mock(DatabaseConfig.class);
private final CryptoComponent crypto = context.mock(CryptoComponent.class);
private final PasswordStrengthEstimator estimator =
context.mock(PasswordStrengthEstimator.class);
@@ -84,9 +77,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
oneOf(accountManager).setDatabaseKey(key);
}});
SetupControllerImpl s = new SetupControllerImpl(briarPrefs,
accountManager, databaseConfig, cryptoExecutor, crypto,
estimator, identityManager);
SetupControllerImpl s = new SetupControllerImpl(accountManager,
cryptoExecutor, crypto, estimator, identityManager);
s.setSetupActivity(setupActivity);
AtomicBoolean called = new AtomicBoolean(false);