mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 19:59:05 +01:00
Switched AppBus for ResultHandler, Controller for Helper. Added the basics for LifecycleControllers and implemented it for BriarActivity and NavDrawerActivity
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
public interface ActivityLifecycleController {
|
||||
void onActivityCreate();
|
||||
|
||||
void onActivityResume();
|
||||
|
||||
void onActivityPause();
|
||||
|
||||
void onActivityDestroy();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
|
||||
public interface BriarController extends ActivityLifecycleController {
|
||||
void runOnDbThread(final Runnable task);
|
||||
|
||||
void startAndBindService();
|
||||
|
||||
void unbindService();
|
||||
|
||||
boolean encryptionKey();
|
||||
|
||||
void signOut(ResultHandler<Void, RuntimeException> eventHandler);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.CallSuper;
|
||||
|
||||
import org.briarproject.android.BriarService;
|
||||
import org.briarproject.android.BriarService.BriarServiceConnection;
|
||||
import org.briarproject.api.db.DatabaseConfig;
|
||||
import org.briarproject.api.db.DatabaseExecutor;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class BriarControllerImp implements BriarController {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(BriarControllerImp.class.getName());
|
||||
|
||||
@Inject
|
||||
protected BriarServiceConnection serviceConnection;
|
||||
@Inject
|
||||
protected DatabaseConfig databaseConfig;
|
||||
// Fields that are accessed from background threads must be volatile
|
||||
@Inject
|
||||
@DatabaseExecutor
|
||||
protected volatile Executor dbExecutor;
|
||||
@Inject
|
||||
protected volatile LifecycleManager lifecycleManager;
|
||||
@Inject
|
||||
protected Activity activity;
|
||||
|
||||
private boolean bound = false;
|
||||
|
||||
@Inject
|
||||
public BriarControllerImp() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@CallSuper
|
||||
public void onActivityCreate() {
|
||||
if (databaseConfig.getEncryptionKey() != null) startAndBindService();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CallSuper
|
||||
public void onActivityResume() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CallSuper
|
||||
public void onActivityPause() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@CallSuper
|
||||
public void onActivityDestroy() {
|
||||
unbindService();
|
||||
}
|
||||
|
||||
public void startAndBindService() {
|
||||
activity.startService(new Intent(activity, BriarService.class));
|
||||
bound = activity.bindService(new Intent(activity, BriarService.class),
|
||||
serviceConnection, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean encryptionKey() {
|
||||
return databaseConfig.getEncryptionKey() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void signOut(final ResultHandler<Void, RuntimeException> eventHandler) {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Wait for the service to finish starting up
|
||||
IBinder binder = serviceConnection.waitForBinder();
|
||||
BriarService service = ((BriarService.BriarBinder) binder).getService();
|
||||
service.waitForStartup();
|
||||
// Shut down the service and wait for it to shut down
|
||||
LOG.info("Shutting down service");
|
||||
service.shutdown();
|
||||
service.waitForShutdown();
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warning("Interrupted while waiting for service");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
eventHandler.onResult(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
public void unbindService() {
|
||||
if (bound) activity.unbindService(serviceConnection);
|
||||
}
|
||||
|
||||
public void runOnDbThread(final Runnable task) {
|
||||
dbExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
lifecycleManager.waitForDatabase();
|
||||
task.run();
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warning("Interrupted while waiting for database");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
public interface ConfigController {
|
||||
String getEncryptedDatabaseKey();
|
||||
|
||||
void clearPrefs();
|
||||
|
||||
boolean initialized();
|
||||
}
|
||||
@@ -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 ConfigControllerImp implements ConfigController {
|
||||
|
||||
private final static String PREF_DB_KEY = "key";
|
||||
|
||||
@Inject
|
||||
protected SharedPreferences briarPrefs;
|
||||
@Inject
|
||||
protected volatile DatabaseConfig databaseConfig;
|
||||
|
||||
@Inject
|
||||
public ConfigControllerImp() {
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
public class EncryptedKeyNullException extends NullPointerException {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Encrypted key can't be null";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
|
||||
public interface NavDrawerController extends BriarController {
|
||||
void setTransportListener(TransportStateListener transportListener);
|
||||
|
||||
boolean transportRunning(TransportId transportId);
|
||||
|
||||
void storeLocalAuthor(LocalAuthor author,
|
||||
ResultHandler<Void, DbException> resultHandler);
|
||||
|
||||
LocalAuthor removeAuthorHandle(long handle);
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import org.briarproject.android.api.ReferenceManager;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventBus;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.TransportDisabledEvent;
|
||||
import org.briarproject.api.event.TransportEnabledEvent;
|
||||
import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.identity.LocalAuthor;
|
||||
import org.briarproject.api.plugins.Plugin;
|
||||
import org.briarproject.api.plugins.PluginManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
public class NavDrawerControllerImp extends BriarControllerImp
|
||||
implements NavDrawerController, EventListener {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(NavDrawerControllerImp.class.getName());
|
||||
|
||||
@Inject
|
||||
protected ReferenceManager referenceManager;
|
||||
@Inject
|
||||
protected volatile IdentityManager identityManager;
|
||||
@Inject
|
||||
protected PluginManager pluginManager;
|
||||
@Inject
|
||||
protected volatile EventBus eventBus;
|
||||
@Inject
|
||||
protected Activity activity;
|
||||
|
||||
private List<Plugin> transports = new ArrayList<Plugin>();
|
||||
|
||||
private TransportStateListener transportStateListener;
|
||||
|
||||
@Inject
|
||||
public NavDrawerControllerImp() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreate() {
|
||||
super.onActivityCreate();
|
||||
initializeTransports();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResume() {
|
||||
super.onActivityResume();
|
||||
eventBus.addListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPause() {
|
||||
super.onActivityPause();
|
||||
eventBus.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof TransportEnabledEvent) {
|
||||
TransportId id = ((TransportEnabledEvent) e).getTransportId();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("TransportEnabledEvent: " + id.getString());
|
||||
}
|
||||
transportStateUpdate(id, true);
|
||||
} else if (e instanceof TransportDisabledEvent) {
|
||||
TransportId id = ((TransportDisabledEvent) e).getTransportId();
|
||||
if (LOG.isLoggable(INFO)) {
|
||||
LOG.info("TransportDisabledEvent: " + id.getString());
|
||||
}
|
||||
transportStateUpdate(id, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void transportStateUpdate(final TransportId id, final boolean enabled) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (transportStateListener != null) {
|
||||
transportStateListener.stateUpdate(id, enabled);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeTransports() {
|
||||
transports.clear();
|
||||
transports.add(pluginManager.getPlugin(new TransportId("tor")));
|
||||
transports.add(pluginManager.getPlugin(new TransportId("bt")));
|
||||
transports.add(pluginManager.getPlugin(new TransportId("lan")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransportListener(TransportStateListener transportListener) {
|
||||
this.transportStateListener = transportListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transportRunning(TransportId transportId) {
|
||||
for (Plugin transport : transports) {
|
||||
if (transport.getId().equals(transportId)) {
|
||||
return transport.isRunning();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeLocalAuthor(final LocalAuthor author,
|
||||
final ResultHandler<Void, DbException> resultHandler) {
|
||||
runOnDbThread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
identityManager.addLocalAuthor(author);
|
||||
long duration = System.currentTimeMillis() - now;
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Storing author took " + duration + " ms");
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultHandler.onResult(null);
|
||||
}
|
||||
});
|
||||
} catch (final DbException e) {
|
||||
if (LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultHandler.onException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalAuthor removeAuthorHandle(long handle) {
|
||||
return referenceManager.removeReference(handle,
|
||||
LocalAuthor.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
public interface PasswordController extends ConfigController {
|
||||
void validatePassword(String password,
|
||||
ResultHandler<Boolean, EncryptedKeyNullException> resultHandler);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
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 PasswordControllerImp extends ConfigControllerImp
|
||||
implements PasswordController {
|
||||
|
||||
@Inject
|
||||
@CryptoExecutor
|
||||
protected Executor cryptoExecutor;
|
||||
@Inject
|
||||
protected CryptoComponent crypto;
|
||||
@Inject
|
||||
protected Activity activity;
|
||||
|
||||
@Inject
|
||||
public PasswordControllerImp() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validatePassword(final String password,
|
||||
final ResultHandler<Boolean, EncryptedKeyNullException> resultHandler) {
|
||||
final byte[] encrypted = getEncryptedKey();
|
||||
if (encrypted == null) {
|
||||
resultHandler.onException(new EncryptedKeyNullException());
|
||||
}
|
||||
cryptoExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
byte[] key = crypto.decryptWithPassword(encrypted, password);
|
||||
if (key == null) {
|
||||
onPasswordValidated(false, resultHandler);
|
||||
} else {
|
||||
databaseConfig.setEncryptionKey(new SecretKey(key));
|
||||
onPasswordValidated(true, resultHandler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onPasswordValidated(final boolean validated,
|
||||
final ResultHandler<Boolean, EncryptedKeyNullException> resultHandler) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultHandler.onResult(validated);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private byte[] getEncryptedKey() {
|
||||
String hex = getEncryptedDatabaseKey();
|
||||
return hex == null ? null : StringUtils.fromHexString(hex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
public interface ResultHandler<R, E> {
|
||||
void onResult(R result);
|
||||
void onException(E exception);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
public interface SetupController {
|
||||
float estimatePasswordStrength(String password);
|
||||
|
||||
void createIdentity(String nickname, String password,
|
||||
ResultHandler<Long, RuntimeException> resultHandler);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import org.briarproject.android.BaseActivity;
|
||||
import org.briarproject.android.api.ReferenceManager;
|
||||
import org.briarproject.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 SetupControllerImp implements SetupController {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(SetupControllerImp.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 SetupControllerImp() {
|
||||
|
||||
}
|
||||
|
||||
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, RuntimeException> resultHandler) {
|
||||
cryptoExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
SecretKey key = crypto.generateSecretKey();
|
||||
databaseConfig.setEncryptionKey(key);
|
||||
String hex = encryptDatabaseKey(key, password);
|
||||
storeEncryptedDatabaseKey(hex);
|
||||
final LocalAuthor localAuthor = createLocalAuthor(nickname);
|
||||
long handle = referenceManager.putReference(localAuthor,
|
||||
LocalAuthor.class);
|
||||
onIdentityCreated(handle, resultHandler);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onIdentityCreated(final long handle,
|
||||
final ResultHandler<Long, RuntimeException> resultHandler) {
|
||||
activity.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultHandler.onResult(handle);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void storeEncryptedDatabaseKey(final String hex) {
|
||||
SharedPreferences.Editor editor = briarPrefs.edit();
|
||||
editor.putString(PREF_DB_KEY, hex);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.briarproject.android.controller;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
|
||||
public interface TransportStateListener {
|
||||
void stateUpdate(TransportId id, boolean enabled);
|
||||
}
|
||||
Reference in New Issue
Block a user