Switched AppBus for ResultHandler, Controller for Helper. Added the basics for LifecycleControllers and implemented it for BriarActivity and NavDrawerActivity

This commit is contained in:
Ernir Erlingsson
2016-04-07 12:54:23 +02:00
parent 27098db18f
commit a14e981236
32 changed files with 584 additions and 356 deletions

View File

@@ -6,14 +6,19 @@ import android.content.SharedPreferences;
import android.os.Bundle;
import org.briarproject.android.contact.ContactListFragment;
import org.briarproject.android.controller.BriarController;
import org.briarproject.android.controller.BriarControllerImp;
import org.briarproject.android.controller.NavDrawerController;
import org.briarproject.android.controller.NavDrawerControllerImp;
import org.briarproject.android.controller.TransportStateListener;
import org.briarproject.android.forum.ForumListFragment;
import org.briarproject.android.fragment.BaseFragment;
import org.briarproject.android.helper.PasswordHelper;
import org.briarproject.android.helper.PasswordHelperImp;
import org.briarproject.android.helper.SetupHelper;
import org.briarproject.android.helper.SetupHelperImp;
import org.briarproject.android.helper.ConfigHelper;
import org.briarproject.android.helper.ConfigHelperImp;
import org.briarproject.android.controller.PasswordController;
import org.briarproject.android.controller.PasswordControllerImp;
import org.briarproject.android.controller.SetupController;
import org.briarproject.android.controller.SetupControllerImp;
import org.briarproject.android.controller.ConfigController;
import org.briarproject.android.controller.ConfigControllerImp;
import org.briarproject.android.keyagreement.ChooseIdentityFragment;
import org.briarproject.android.keyagreement.ShowQrCodeFragment;
@@ -22,6 +27,8 @@ import javax.inject.Named;
import dagger.Module;
import dagger.Provides;
import static org.briarproject.android.BriarService.*;
@Module
public class ActivityModule {
@@ -31,6 +38,12 @@ public class ActivityModule {
this.activity = activity;
}
@ActivityScope
@Provides
BaseActivity providesBaseActivity() {
return activity;
}
@ActivityScope
@Provides
Activity providesActivity() {
@@ -39,14 +52,16 @@ public class ActivityModule {
@ActivityScope
@Provides
SetupHelper provideSetupHelper(SetupHelperImp setupHelperImp) {
return setupHelperImp;
SetupController provideSetupController(
SetupControllerImp setupControllerImp) {
return setupControllerImp;
}
@ActivityScope
@Provides
ConfigHelper provideConfigHelper(ConfigHelperImp configHelperImp) {
return configHelperImp;
ConfigController provideConfigController(
ConfigControllerImp configControllerImp) {
return configControllerImp;
}
@ActivityScope
@@ -57,8 +72,35 @@ public class ActivityModule {
@ActivityScope
@Provides
PasswordHelper providePasswordHelper(PasswordHelperImp passwordHelperImp) {
return passwordHelperImp;
PasswordController providePasswordController(
PasswordControllerImp passwordControllerImp) {
return passwordControllerImp;
}
@ActivityScope
@Provides
BriarController provideBriarController(
BriarControllerImp briarControllerImp) {
activity.addLifecycleController(briarControllerImp);
return briarControllerImp;
}
@ActivityScope
@Provides
NavDrawerController provideNavDrawerController(
NavDrawerControllerImp navDrawerControllerImp) {
activity.addLifecycleController(navDrawerControllerImp);
if (activity instanceof TransportStateListener) {
navDrawerControllerImp
.setTransportListener((TransportStateListener) activity);
}
return navDrawerControllerImp;
}
@ActivityScope
@Provides
BriarServiceConnection provideBriarServiceConnection() {
return new BriarServiceConnection();
}
@Provides

View File

@@ -4,9 +4,6 @@ import org.briarproject.CoreEagerSingletons;
import org.briarproject.CoreModule;
import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.api.ReferenceManager;
import org.briarproject.android.contact.ContactListFragment;
import org.briarproject.android.contact.ConversationActivity;
import org.briarproject.android.event.AppBus;
import org.briarproject.api.contact.ContactExchangeTask;
import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.crypto.CryptoComponent;
@@ -68,8 +65,6 @@ public interface AndroidComponent extends CoreEagerSingletons {
EventBus eventBus();
AppBus appEventBus();
InvitationTaskFactory invitationTaskFactory();
AndroidNotificationManager androidNotificationManager();

View File

@@ -2,29 +2,31 @@ package org.briarproject.android;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.CallSuper;
import android.os.PersistableBundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import org.briarproject.android.event.AppBus;
import org.briarproject.android.event.ErrorEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import org.briarproject.android.controller.ActivityLifecycleController;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS;
public abstract class BaseActivity extends AppCompatActivity implements
EventListener {
public abstract class BaseActivity extends AppCompatActivity {
protected ActivityComponent activityComponent;
@Inject
protected AppBus appBus;
private List<ActivityLifecycleController> lifecycleControllers =
new ArrayList<ActivityLifecycleController>();
public void addLifecycleController(
ActivityLifecycleController lifecycleController) {
this.lifecycleControllers.add(lifecycleController);
}
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -43,23 +45,37 @@ public abstract class BaseActivity extends AppCompatActivity implements
injectActivity(activityComponent);
}
@Override
public void onPostCreate(Bundle savedInstanceState,
PersistableBundle persistentState) {
super.onPostCreate(savedInstanceState, persistentState);
for (ActivityLifecycleController alc : lifecycleControllers) {
alc.onActivityCreate();
}
}
@Override
protected void onResume() {
super.onResume();
appBus.addListener(this);
for (ActivityLifecycleController alc : lifecycleControllers) {
alc.onActivityResume();
}
}
@Override
protected void onPause() {
appBus.removeListener(this);
super.onPause();
for (ActivityLifecycleController alc : lifecycleControllers) {
alc.onActivityPause();
}
}
@Override
@CallSuper
public void eventOccurred(Event e) {
if (e instanceof ErrorEvent) {
finish();
protected void onDestroy() {
super.onDestroy();
for (ActivityLifecycleController alc : lifecycleControllers) {
alc.onActivityDestroy();
}
}

View File

@@ -8,6 +8,8 @@ import android.os.IBinder;
import org.briarproject.android.BriarService.BriarBinder;
import org.briarproject.android.BriarService.BriarServiceConnection;
import org.briarproject.android.controller.BriarController;
import org.briarproject.android.controller.ResultHandler;
import org.briarproject.android.panic.ExitActivity;
import org.briarproject.api.db.DatabaseConfig;
import org.briarproject.api.db.DatabaseExecutor;
@@ -37,12 +39,12 @@ public abstract class BriarActivity extends BaseActivity {
private static final Logger LOG =
Logger.getLogger(BriarActivity.class.getName());
/*
private final BriarServiceConnection serviceConnection =
new BriarServiceConnection();
@Inject
protected DatabaseConfig databaseConfig;
DatabaseConfig databaseConfig;
private boolean bound = false;
// Fields that are accessed from background threads must be volatile
@@ -51,19 +53,23 @@ public abstract class BriarActivity extends BaseActivity {
protected volatile Executor dbExecutor;
@Inject
protected volatile LifecycleManager lifecycleManager;
*/
@Inject
protected BriarController briarController;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
if (databaseConfig.getEncryptionKey() != null) startAndBindService();
briarController.startAndBindService();
// if (databaseConfig.getEncryptionKey() != null) startAndBindService();
}
@Override
protected void onActivityResult(int request, int result, Intent data) {
super.onActivityResult(request, result, data);
if (request == REQUEST_PASSWORD) {
if (result == RESULT_OK) startAndBindService();
if (result == RESULT_OK) briarController.startAndBindService();
else finish();
}
}
@@ -71,7 +77,7 @@ public abstract class BriarActivity extends BaseActivity {
@Override
public void onResume() {
super.onResume();
if (databaseConfig.getEncryptionKey() == null && !isFinishing()) {
if (!briarController.encryptionKey() && !isFinishing()) {
Intent i = new Intent(this, PasswordActivity.class);
i.setFlags(FLAG_ACTIVITY_NO_ANIMATION | FLAG_ACTIVITY_SINGLE_TOP);
startActivityForResult(i, REQUEST_PASSWORD);
@@ -81,41 +87,22 @@ public abstract class BriarActivity extends BaseActivity {
@Override
public void onDestroy() {
super.onDestroy();
unbindService();
}
private void startAndBindService() {
startService(new Intent(this, BriarService.class));
bound = bindService(new Intent(this, BriarService.class),
serviceConnection, 0);
}
private void unbindService() {
if (bound) unbindService(serviceConnection);
briarController.unbindService();
}
protected void signOut(final boolean removeFromRecentApps) {
// Use a new thread to avoid deadlock with executor tasks
new Thread() {
briarController.signOut(new ResultHandler<Void, RuntimeException>() {
@Override
public void run() {
try {
// Wait for the service to finish starting up
IBinder binder = serviceConnection.waitForBinder();
BriarService service = ((BriarBinder) binder).getService();
service.waitForStartup();
// Shut down the service and wait for it to shut down
LOG.info("Shutting down service");
service.shutdown();
service.waitForShutdown();
} catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for service");
Thread.currentThread().interrupt();
}
public void onResult(Void result) {
if (removeFromRecentApps) startExitActivity();
else finishAndExit();
}
}.start();
@Override
public void onException(RuntimeException exception) {
// TODO ?
}
});
}
protected void signOut() {
@@ -123,44 +110,25 @@ public abstract class BriarActivity extends BaseActivity {
}
private void startExitActivity() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(BriarActivity.this,
ExitActivity.class);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK
| FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| FLAG_ACTIVITY_NO_ANIMATION);
if (Build.VERSION.SDK_INT >= 11)
intent.addFlags(FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
});
Intent intent = new Intent(BriarActivity.this,
ExitActivity.class);
intent.addFlags(FLAG_ACTIVITY_NEW_TASK
| FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| FLAG_ACTIVITY_NO_ANIMATION);
if (Build.VERSION.SDK_INT >= 11)
intent.addFlags(FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
private void finishAndExit() {
runOnUiThread(new Runnable() {
public void run() {
if (Build.VERSION.SDK_INT >= 21) finishAndRemoveTask();
else finish();
LOG.info("Exiting");
System.exit(0);
}
});
if (Build.VERSION.SDK_INT >= 21) finishAndRemoveTask();
else finish();
LOG.info("Exiting");
System.exit(0);
}
public void runOnDbThread(final Runnable task) {
dbExecutor.execute(new Runnable() {
public void run() {
try {
lifecycleManager.waitForDatabase();
task.run();
} catch (InterruptedException e) {
LOG.warning("Interrupted while waiting for database");
Thread.currentThread().interrupt();
}
}
});
briarController.runOnDbThread(task);
}
protected void finishOnUiThread() {

View File

@@ -180,7 +180,7 @@ public class BriarService extends Service {
/** Starts the shutdown process. */
public void shutdown() {
stopSelf(); // This will call onDestroy()
stopSelf(); // This will call onActivityDestroy()
}
public class BriarBinder extends Binder {

View File

@@ -14,28 +14,19 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
import org.briarproject.R;
import org.briarproject.android.contact.ContactListFragment;
import org.briarproject.android.forum.ForumListFragment;
import org.briarproject.android.controller.NavDrawerController;
import org.briarproject.android.controller.ResultHandler;
import org.briarproject.android.controller.TransportStateListener;
import org.briarproject.android.fragment.BaseFragment;
import org.briarproject.android.util.CustomAnimations;
import org.briarproject.api.TransportId;
import org.briarproject.android.api.ReferenceManager;
import org.briarproject.api.db.DbException;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.TransportDisabledEvent;
import org.briarproject.api.event.TransportEnabledEvent;
import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.plugins.Plugin;
import org.briarproject.api.plugins.PluginManager;
import java.util.ArrayList;
import java.util.List;
@@ -43,11 +34,8 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
public class NavDrawerActivity extends BriarFragmentActivity implements
BaseFragment.BaseFragmentListener, EventListener {
BaseFragment.BaseFragmentListener, TransportStateListener {
public final static String PREF_SEEN_WELCOME_MESSAGE = "welcome_message";
@@ -60,14 +48,7 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
private ActionBarDrawerToggle drawerToggle;
@Inject
protected ReferenceManager referenceManager;
// Fields that are accessed from background threads must be volatile
@Inject
protected volatile IdentityManager identityManager;
@Inject
protected PluginManager pluginManager;
@Inject
protected volatile EventBus eventBus;
NavDrawerController controller;
private Toolbar toolbar;
private DrawerLayout drawerLayout;
@@ -106,11 +87,11 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
setContentView(R.layout.activity_nav_drawer);
toolbar = (Toolbar)findViewById(R.id.toolbar);
drawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
transportsView = (GridView)findViewById(R.id.transportsView);
progressTitle = (TextView)findViewById(R.id.title_progress_bar);
progressViewGroup = (ViewGroup)findViewById(R.id.container_progress);
toolbar = (Toolbar) findViewById(R.id.toolbar);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
transportsView = (GridView) findViewById(R.id.transportsView);
progressTitle = (TextView) findViewById(R.id.title_progress_bar);
progressViewGroup = (ViewGroup) findViewById(R.id.container_progress);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@@ -151,22 +132,14 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
@Override
public void onResume() {
super.onResume();
eventBus.addListener(this);
updateTransports();
}
@Override
protected void onPause() {
super.onPause();
eventBus.removeListener(this);
}
private void checkAuthorHandle(Intent intent) {
long handle = intent.getLongExtra(KEY_LOCAL_AUTHOR_HANDLE, -1);
if (handle != -1) {
LocalAuthor a = controller.removeAuthorHandle(handle);
// The activity was launched from the setup wizard
LocalAuthor a = referenceManager.removeReference(handle,
LocalAuthor.class);
if (a != null) {
showLoadingScreen(true, R.string.progress_title_please_wait);
storeLocalAuthor(a);
@@ -185,27 +158,18 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
}
private void storeLocalAuthor(final LocalAuthor a) {
runOnDbThread(new Runnable() {
public void run() {
try {
long now = System.currentTimeMillis();
identityManager.addLocalAuthor(a);
long duration = System.currentTimeMillis() - now;
if (LOG.isLoggable(INFO))
LOG.info("Storing author took " + duration + " ms");
controller.storeLocalAuthor(a,
new ResultHandler<Void, DbException>() {
@Override
public void onResult(Void result) {
hideLoadingScreen();
}
runOnUiThread(new Runnable() {
public void run() {
hideLoadingScreen();
}
});
@Override
public void onException(DbException exception) {
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
}
}
});
}
});
}
public void onNavigationClick(View view) {
@@ -281,24 +245,21 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
Transport tor = new Transport();
tor.id = new TransportId("tor");
Plugin torPlugin = pluginManager.getPlugin(tor.id);
tor.enabled = torPlugin != null && torPlugin.isRunning();
tor.enabled = controller.transportRunning(tor.id);
tor.iconId = R.drawable.transport_tor;
tor.textId = R.string.transport_tor;
transports.add(tor);
Transport bt = new Transport();
bt.id = new TransportId("bt");
Plugin btPlugin = pluginManager.getPlugin(bt.id);
bt.enabled = btPlugin != null && btPlugin.isRunning();
bt.enabled = controller.transportRunning(bt.id);
bt.iconId = R.drawable.transport_bt;
bt.textId = R.string.transport_bt;
transports.add(bt);
Transport lan = new Transport();
lan.id = new TransportId("lan");
Plugin lanPlugin = pluginManager.getPlugin(lan.id);
lan.enabled = lanPlugin != null && lanPlugin.isRunning();
lan.enabled = controller.transportRunning(lan.id);
lan.iconId = R.drawable.transport_lan;
lan.textId = R.string.transport_lan;
transports.add(lan);
@@ -365,27 +326,14 @@ public class NavDrawerActivity extends BriarFragmentActivity implements
private void updateTransports() {
if (transports == null || transportsAdapter == null) return;
for (Transport t : transports) {
Plugin plugin = pluginManager.getPlugin(t.id);
t.enabled = plugin != null && plugin.isRunning();
t.enabled = controller.transportRunning(t.id);
}
transportsAdapter.notifyDataSetChanged();
}
@Override
public void eventOccurred(Event e) {
if (e instanceof TransportEnabledEvent) {
TransportId id = ((TransportEnabledEvent) e).getTransportId();
if (LOG.isLoggable(INFO)) {
LOG.info("TransportEnabledEvent: " + id.getString());
}
setTransport(id, true);
} else if (e instanceof TransportDisabledEvent) {
TransportId id = ((TransportDisabledEvent) e).getTransportId();
if (LOG.isLoggable(INFO)) {
LOG.info("TransportDisabledEvent: " + id.getString());
}
setTransport(id, false);
}
public void stateUpdate(TransportId id, boolean enabled) {
setTransport(id, enabled);
}
private static class Transport {

View File

@@ -16,10 +16,10 @@ import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import org.briarproject.R;
import org.briarproject.android.event.PasswordValidateEvent;
import org.briarproject.android.helper.PasswordHelper;
import org.briarproject.android.controller.EncryptedKeyNullException;
import org.briarproject.android.controller.PasswordController;
import org.briarproject.android.controller.ResultHandler;
import org.briarproject.android.util.AndroidUtils;
import org.briarproject.api.event.Event;
import javax.inject.Inject;
@@ -36,7 +36,7 @@ public class PasswordActivity extends BaseActivity {
private EditText password;
@Inject
PasswordHelper passwordHelper;
PasswordController passwordHelper;
@Override
public void onCreate(Bundle state) {
@@ -125,22 +125,23 @@ public class PasswordActivity extends BaseActivity {
hideSoftKeyboard(password);
signInButton.setVisibility(INVISIBLE);
progress.setVisibility(VISIBLE);
passwordHelper.validatePassword(password.getText().toString());
}
passwordHelper.validatePassword(password.getText().toString(),
new ResultHandler<Boolean, EncryptedKeyNullException>() {
@Override
public void onResult(Boolean result) {
if (result != null && result) {
setResult(RESULT_OK);
finish();
} else {
tryAgain();
}
}
@Override
public void eventOccurred(Event e) {
super.eventOccurred(e);
if (e instanceof PasswordValidateEvent) {
boolean validated = ((PasswordValidateEvent)e).passwordValidated();
if (validated) {
setResult(RESULT_OK);
finish();
}
else {
tryAgain();
}
}
@Override
public void onException(EncryptedKeyNullException e) {
// TODO ?
}
});
}
private void tryAgain() {

View File

@@ -15,24 +15,12 @@ import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import org.briarproject.R;
import org.briarproject.android.event.LocalAuthorCreatedEvent;
import org.briarproject.android.helper.SetupHelper;
import org.briarproject.android.controller.ResultHandler;
import org.briarproject.android.controller.SetupController;
import org.briarproject.android.util.AndroidUtils;
import org.briarproject.android.util.StrengthMeter;
import org.briarproject.android.api.ReferenceManager;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.crypto.KeyPair;
import org.briarproject.api.crypto.PasswordStrengthEstimator;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DatabaseConfig;
import org.briarproject.api.event.Event;
import org.briarproject.api.identity.AuthorFactory;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.util.StringUtils;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import org.briarproject.util.StringUtils;
import javax.inject.Inject;
@@ -40,7 +28,6 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static java.util.logging.Level.INFO;
import static org.briarproject.android.TestingConstants.PREVENT_SCREENSHOTS;
import static org.briarproject.api.crypto.PasswordStrengthEstimator.WEAK;
import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
@@ -49,7 +36,7 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
OnEditorActionListener {
@Inject
SetupHelper setupHelper;
SetupController setupController;
TextInputLayout nicknameEntryWrapper;
TextInputLayout passwordEntryWrapper;
@@ -120,8 +107,7 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
String firstPassword = passwordEntry.getText().toString();
String secondPassword = passwordConfirmation.getText().toString();
boolean passwordsMatch = firstPassword.equals(secondPassword);
// float strength = strengthEstimator.estimateStrength(firstPassword);
float strength = setupHelper.estimatePasswordStrength(firstPassword);
float strength = setupController.estimatePasswordStrength(firstPassword);
strengthMeter.setStrength(strength);
AndroidUtils.setError(nicknameEntryWrapper,
getString(R.string.name_too_long),
@@ -148,19 +134,22 @@ public class SetupActivity extends BaseActivity implements OnClickListener,
progress.setVisibility(VISIBLE);
final String nickname = nicknameEntry.getText().toString();
final String password = passwordEntry.getText().toString();
setupHelper.createIdentity(nickname, password);
setupController.createIdentity(nickname, password,
new ResultHandler<Long, RuntimeException>() {
@Override
public void onResult(Long result) {
if (result != null)
showMain(result);
}
@Override
public void onException(RuntimeException exception) {
}
});
}
@Override
public void eventOccurred(Event e) {
super.eventOccurred(e);
if (e instanceof LocalAuthorCreatedEvent) {
long handle = ((LocalAuthorCreatedEvent)e).getAuthorHandle();
showDashboard(handle);
}
}
private void showDashboard(final long handle) {
private void showMain(final long handle) {
Intent i = new Intent(SetupActivity.this,
NavDrawerActivity.class);
i.putExtra(BriarActivity.KEY_LOCAL_AUTHOR_HANDLE, handle);

View File

@@ -9,7 +9,7 @@ import android.os.StrictMode.VmPolicy;
import android.support.v7.preference.PreferenceManager;
import org.briarproject.R;
import org.briarproject.android.helper.ConfigHelper;
import org.briarproject.android.controller.ConfigController;
import org.briarproject.android.util.AndroidUtils;
import java.util.logging.Logger;
@@ -28,7 +28,7 @@ public class SplashScreenActivity extends BaseActivity {
private static final long EXPIRY_DATE = 1464735600 * 1000L;
@Inject
ConfigHelper configHelper;
ConfigController configController;
public SplashScreenActivity() {
Logger.getLogger("").setLevel(DEFAULT_LOG_LEVEL);
@@ -62,10 +62,10 @@ public class SplashScreenActivity extends BaseActivity {
LOG.info("Expired");
startActivity(new Intent(this, ExpiredActivity.class));
} else {
if (configHelper.initialized()) {
if (configController.initialized()) {
startActivity(new Intent(this, NavDrawerActivity.class));
} else {
configHelper.clearPrefs();
configController.clearPrefs();
AndroidUtils.deleteAppData(this);
startActivity(new Intent(this, SetupActivity.class));
}

View File

@@ -0,0 +1,11 @@
package org.briarproject.android.controller;
public interface ActivityLifecycleController {
void onActivityCreate();
void onActivityResume();
void onActivityPause();
void onActivityDestroy();
}

View File

@@ -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);
}

View File

@@ -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();
}
}
});
}
}

View File

@@ -1,6 +1,6 @@
package org.briarproject.android.helper;
package org.briarproject.android.controller;
public interface ConfigHelper {
public interface ConfigController {
String getEncryptedDatabaseKey();
void clearPrefs();

View File

@@ -1,4 +1,4 @@
package org.briarproject.android.helper;
package org.briarproject.android.controller;
import android.content.SharedPreferences;
@@ -6,7 +6,7 @@ import org.briarproject.api.db.DatabaseConfig;
import javax.inject.Inject;
public class ConfigHelperImp implements ConfigHelper {
public class ConfigControllerImp implements ConfigController {
private final static String PREF_DB_KEY = "key";
@@ -16,7 +16,7 @@ public class ConfigHelperImp implements ConfigHelper {
protected volatile DatabaseConfig databaseConfig;
@Inject
public ConfigHelperImp() {
public ConfigControllerImp() {
}

View File

@@ -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";
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,6 @@
package org.briarproject.android.controller;
public interface PasswordController extends ConfigController {
void validatePassword(String password,
ResultHandler<Boolean, EncryptedKeyNullException> resultHandler);
}

View File

@@ -1,10 +1,7 @@
package org.briarproject.android.helper;
package org.briarproject.android.controller;
import android.app.Activity;
import org.briarproject.android.event.AppBus;
import org.briarproject.android.event.ErrorEvent;
import org.briarproject.android.event.PasswordValidateEvent;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.crypto.SecretKey;
@@ -14,8 +11,8 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
public class PasswordHelperImp extends ConfigHelperImp
implements PasswordHelper {
public class PasswordControllerImp extends ConfigControllerImp
implements PasswordController {
@Inject
@CryptoExecutor
@@ -24,38 +21,38 @@ public class PasswordHelperImp extends ConfigHelperImp
protected CryptoComponent crypto;
@Inject
protected Activity activity;
@Inject
protected AppBus appBus;
@Inject
public PasswordHelperImp() {
public PasswordControllerImp() {
}
@Override
public void validatePassword(final String password) {
public void validatePassword(final String password,
final ResultHandler<Boolean, EncryptedKeyNullException> resultHandler) {
final byte[] encrypted = getEncryptedKey();
if (encrypted == null) {
appBus.broadcast(new ErrorEvent());
resultHandler.onException(new EncryptedKeyNullException());
}
cryptoExecutor.execute(new Runnable() {
public void run() {
byte[] key = crypto.decryptWithPassword(encrypted, password);
if (key == null) {
onPasswordValidated(false);
onPasswordValidated(false, resultHandler);
} else {
databaseConfig.setEncryptionKey(new SecretKey(key));
onPasswordValidated(true);
onPasswordValidated(true, resultHandler);
}
}
});
}
private void onPasswordValidated(final boolean validated) {
private void onPasswordValidated(final boolean validated,
final ResultHandler<Boolean, EncryptedKeyNullException> resultHandler) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
appBus.broadcast(new PasswordValidateEvent(validated));
resultHandler.onResult(validated);
}
});
}
@@ -63,6 +60,6 @@ public class PasswordHelperImp extends ConfigHelperImp
private byte[] getEncryptedKey() {
String hex = getEncryptedDatabaseKey();
return hex == null? null : StringUtils.fromHexString(hex);
return hex == null ? null : StringUtils.fromHexString(hex);
}
}

View File

@@ -0,0 +1,6 @@
package org.briarproject.android.controller;
public interface ResultHandler<R, E> {
void onResult(R result);
void onException(E exception);
}

View File

@@ -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);
}

View File

@@ -1,11 +1,10 @@
package org.briarproject.android.helper;
package org.briarproject.android.controller;
import android.app.Activity;
import android.content.SharedPreferences;
import org.briarproject.android.BaseActivity;
import org.briarproject.android.api.ReferenceManager;
import org.briarproject.android.event.AppBus;
import org.briarproject.android.event.LocalAuthorCreatedEvent;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.CryptoExecutor;
import org.briarproject.api.crypto.KeyPair;
@@ -23,10 +22,10 @@ import javax.inject.Inject;
import static java.util.logging.Level.INFO;
public class SetupHelperImp implements SetupHelper {
public class SetupControllerImp implements SetupController {
private static final Logger LOG =
Logger.getLogger(SetupHelperImp.class.getName());
Logger.getLogger(SetupControllerImp.class.getName());
private final static String PREF_DB_KEY = "key";
@@ -45,16 +44,13 @@ public class SetupHelperImp implements SetupHelper {
protected volatile AuthorFactory authorFactory;
@Inject
protected volatile ReferenceManager referenceManager;
@Inject
protected Activity activity;
@Inject
protected SharedPreferences briarPrefs;
@Inject
protected AppBus appBus;
@Inject
public SetupHelperImp() {
public SetupControllerImp() {
}
@@ -86,7 +82,8 @@ public class SetupHelperImp implements SetupHelper {
}
@Override
public void createIdentity(final String nickname, final String password) {
public void createIdentity(final String nickname, final String password,
final ResultHandler<Long, RuntimeException> resultHandler) {
cryptoExecutor.execute(new Runnable() {
public void run() {
SecretKey key = crypto.generateSecretKey();
@@ -94,18 +91,20 @@ public class SetupHelperImp implements SetupHelper {
String hex = encryptDatabaseKey(key, password);
storeEncryptedDatabaseKey(hex);
final LocalAuthor localAuthor = createLocalAuthor(nickname);
onIdentityCreated(referenceManager.putReference(localAuthor,
LocalAuthor.class));
long handle = referenceManager.putReference(localAuthor,
LocalAuthor.class);
onIdentityCreated(handle, resultHandler);
}
});
}
private void onIdentityCreated(final long handle) {
private void onIdentityCreated(final long handle,
final ResultHandler<Long, RuntimeException> resultHandler) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
appBus.broadcast(new LocalAuthorCreatedEvent(handle));
resultHandler.onResult(handle);
}
});
}

View File

@@ -0,0 +1,7 @@
package org.briarproject.android.controller;
import org.briarproject.api.TransportId;
public interface TransportStateListener {
void stateUpdate(TransportId id, boolean enabled);
}

View File

@@ -1,6 +0,0 @@
package org.briarproject.android.event;
import org.briarproject.api.event.EventBus;
public interface AppBus extends EventBus{
}

View File

@@ -1,25 +0,0 @@
package org.briarproject.android.event;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;
public class AppBusImp implements AppBus {
private final Collection<EventListener> listeners =
new CopyOnWriteArrayList<EventListener>();
public void addListener(EventListener l) {
listeners.add(l);
}
public void removeListener(EventListener l) {
listeners.remove(l);
}
public void broadcast(Event e) {
for (EventListener l : listeners) l.eventOccurred(e);
}
}

View File

@@ -1,10 +0,0 @@
package org.briarproject.android.event;
import org.briarproject.api.event.Event;
public class ErrorEvent extends Event {
public ErrorEvent() {
}
}

View File

@@ -1,16 +0,0 @@
package org.briarproject.android.event;
import org.briarproject.api.event.Event;
public class LocalAuthorCreatedEvent extends Event {
private final long handle;
public LocalAuthorCreatedEvent(long handle) {
this.handle = handle;
}
public long getAuthorHandle() {
return handle;
}
}

View File

@@ -1,16 +0,0 @@
package org.briarproject.android.event;
import org.briarproject.api.event.Event;
public class PasswordValidateEvent extends Event {
private final boolean passwordValidated;
public PasswordValidateEvent(boolean passwordValidated) {
this.passwordValidated = passwordValidated;
}
public boolean passwordValidated() {
return passwordValidated;
}
}

View File

@@ -1,5 +0,0 @@
package org.briarproject.android.helper;
public interface PasswordHelper extends ConfigHelper {
void validatePassword(String password);
}

View File

@@ -1,6 +0,0 @@
package org.briarproject.android.helper;
public interface SetupHelper {
float estimatePasswordStrength(String password);
void createIdentity(String nickname, String password);
}

View File

@@ -287,7 +287,7 @@ implements InvitationListener {
localInvitationCode, code);
taskHandle = referenceManager.putReference(task, InvitationTask.class);
task.addListener(AddContactActivity.this);
// Add a second listener so we can remove the first in onDestroy(),
// Add a second listener so we can remove the first in onActivityDestroy(),
// allowing the activity to be garbage collected if it's destroyed
task.addListener(new ReferenceCleaner(referenceManager, taskHandle));
task.connect();

View File

@@ -8,11 +8,9 @@ import android.os.Bundle;
import android.support.v7.preference.PreferenceManager;
import org.briarproject.android.ActivityComponent;
import org.briarproject.android.AndroidComponent;
import org.briarproject.android.BriarActivity;
import org.briarproject.android.helper.ConfigHelper;
import org.briarproject.android.controller.ConfigController;
import org.briarproject.android.util.AndroidUtils;
import org.briarproject.api.db.DatabaseConfig;
import org.iilab.IilabEngineeringRSA2048Pin;
import java.util.logging.Logger;
@@ -32,7 +30,7 @@ public class PanicResponderActivity extends BriarActivity {
private static final Logger LOG =
Logger.getLogger(PanicResponderActivity.class.getName());
@Inject protected ConfigHelper configHelper;
@Inject protected ConfigController configController;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -108,7 +106,7 @@ public class PanicResponderActivity extends BriarActivity {
private void deleteAllData() {
androidExecutor.execute(new Runnable() {
public void run() {
configHelper.clearPrefs();
configController.clearPrefs();
// TODO somehow delete/shred the database more thoroughly
AndroidUtils.deleteAppData(PanicResponderActivity.this);
PanicResponder.deleteAllAppData(PanicResponderActivity.this);