mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
@@ -27,7 +27,9 @@ import org.briarproject.bramble.plugin.tcp.AndroidLanTcpPluginFactory;
|
||||
import org.briarproject.bramble.plugin.tor.AndroidTorPluginFactory;
|
||||
import org.briarproject.bramble.util.AndroidUtils;
|
||||
import org.briarproject.bramble.util.StringUtils;
|
||||
import org.briarproject.briar.android.account.DozeHelperModule;
|
||||
import org.briarproject.briar.android.account.LockManagerImpl;
|
||||
import org.briarproject.briar.android.account.SetupModule;
|
||||
import org.briarproject.briar.android.contact.ContactListModule;
|
||||
import org.briarproject.briar.android.forum.ForumModule;
|
||||
import org.briarproject.briar.android.keyagreement.ContactExchangeModule;
|
||||
@@ -64,6 +66,8 @@ import static org.briarproject.bramble.api.reporting.ReportingConstants.DEV_PUBL
|
||||
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
|
||||
|
||||
@Module(includes = {
|
||||
SetupModule.class,
|
||||
DozeHelperModule.class,
|
||||
ContactExchangeModule.class,
|
||||
LoginModule.class,
|
||||
NavDrawerModule.class,
|
||||
|
||||
@@ -81,8 +81,7 @@ public class AuthorNameFragment extends SetupFragment {
|
||||
public void onClick(View view) {
|
||||
Editable text = authorNameInput.getText();
|
||||
if (text != null) {
|
||||
setupController.setAuthorName(text.toString().trim());
|
||||
setupController.showPasswordFragment();
|
||||
viewModel.setAuthorName(text.toString().trim());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,9 +104,15 @@ public class DozeFragment extends SetupFragment
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
next.setVisibility(INVISIBLE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
setupController.createAccount();
|
||||
setNextClicked();
|
||||
viewModel.dozeExceptionConfirmed();
|
||||
}
|
||||
|
||||
@Override
|
||||
void setNextClicked() {
|
||||
super.setNextClicked();
|
||||
|
||||
next.setVisibility(INVISIBLE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
interface DozeHelper {
|
||||
|
||||
boolean needToShowDozeFragment(Context context);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import static org.briarproject.briar.android.account.HuaweiView.needsToBeShown;
|
||||
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
|
||||
|
||||
class DozeHelperImpl implements DozeHelper {
|
||||
@Override
|
||||
public boolean needToShowDozeFragment(Context context) {
|
||||
return needsDozeWhitelisting(context.getApplicationContext()) ||
|
||||
needsToBeShown(context.getApplicationContext());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@Module
|
||||
public class DozeHelperModule {
|
||||
|
||||
@Provides
|
||||
DozeHelper provideDozeHelper() {
|
||||
return new DozeHelperImpl();
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import static org.briarproject.briar.android.util.UiUtils.setError;
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class SetPasswordFragment extends SetupFragment {
|
||||
|
||||
private final static String TAG = SetPasswordFragment.class.getName();
|
||||
|
||||
private TextInputLayout passwordEntryWrapper;
|
||||
@@ -56,7 +55,7 @@ public class SetPasswordFragment extends SetupFragment {
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
requireActivity().setTitle(getString(R.string.setup_password_intro));
|
||||
View v = inflater.inflate(R.layout.fragment_setup_password, container,
|
||||
false);
|
||||
false);
|
||||
|
||||
strengthMeter = v.findViewById(R.id.strength_meter);
|
||||
passwordEntryWrapper = v.findViewById(R.id.password_entry_wrapper);
|
||||
@@ -71,7 +70,7 @@ public class SetPasswordFragment extends SetupFragment {
|
||||
passwordConfirmation.addTextChangedListener(this);
|
||||
nextButton.setOnClickListener(this);
|
||||
|
||||
if (!setupController.needToShowDozeFragment()) {
|
||||
if (!viewModel.needToShowDozeFragment()) {
|
||||
nextButton.setText(R.string.create_account_button);
|
||||
passwordConfirmation.setImeOptions(IME_ACTION_DONE);
|
||||
}
|
||||
@@ -97,7 +96,7 @@ public class SetPasswordFragment extends SetupFragment {
|
||||
|
||||
strengthMeter
|
||||
.setVisibility(password1.length() > 0 ? VISIBLE : INVISIBLE);
|
||||
float strength = setupController.estimatePasswordStrength(password1);
|
||||
float strength = viewModel.estimatePasswordStrength(password1);
|
||||
strengthMeter.setStrength(strength);
|
||||
boolean strongEnough = strength >= QUITE_WEAK;
|
||||
|
||||
@@ -117,14 +116,20 @@ public class SetPasswordFragment extends SetupFragment {
|
||||
IBinder token = passwordEntry.getWindowToken();
|
||||
Object o = getContext().getSystemService(INPUT_METHOD_SERVICE);
|
||||
((InputMethodManager) o).hideSoftInputFromWindow(token, 0);
|
||||
setupController.setPassword(passwordEntry.getText().toString());
|
||||
if (setupController.needToShowDozeFragment()) {
|
||||
setupController.showDozeFragment();
|
||||
} else {
|
||||
nextButton.setVisibility(INVISIBLE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
setupController.createAccount();
|
||||
}
|
||||
|
||||
setNextClicked();
|
||||
viewModel.setPassword(passwordEntry.getText().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
void setNextClicked() {
|
||||
super.setNextClicked();
|
||||
|
||||
passwordEntry.setFocusable(false);
|
||||
passwordConfirmation.setFocusable(false);
|
||||
if (!viewModel.needToShowDozeFragment()) {
|
||||
nextButton.setVisibility(INVISIBLE);
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.R;
|
||||
@@ -15,28 +14,36 @@ import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
||||
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
|
||||
import static org.briarproject.briar.android.BriarApplication.ENTRY_ACTIVITY;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.AUTHOR_NAME;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.CREATED;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.DOZE;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.FAILED;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.SET_PASSWORD;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
public class SetupActivity extends BaseActivity
|
||||
implements BaseFragmentListener {
|
||||
|
||||
private static final String STATE_KEY_AUTHOR_NAME = "authorName";
|
||||
private static final String STATE_KEY_PASSWORD = "password";
|
||||
|
||||
@Inject
|
||||
AccountManager accountManager;
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
SetupViewModel viewModel;
|
||||
|
||||
@Inject
|
||||
SetupController setupController;
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
|
||||
@Nullable
|
||||
private String authorName, password;
|
||||
viewModel = new ViewModelProvider(this, viewModelFactory)
|
||||
.get(SetupViewModel.class);
|
||||
viewModel.getState().observeEvent(this, this::onStateChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle state) {
|
||||
@@ -44,58 +51,27 @@ public class SetupActivity extends BaseActivity
|
||||
// fade-in after splash screen instead of default animation
|
||||
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
|
||||
setContentView(R.layout.activity_fragment_container);
|
||||
}
|
||||
|
||||
if (state == null) {
|
||||
if (accountManager.accountExists()) throw new AssertionError();
|
||||
private void onStateChanged(SetupViewModel.State state) {
|
||||
if (state == AUTHOR_NAME) {
|
||||
showInitialFragment(AuthorNameFragment.newInstance());
|
||||
} else {
|
||||
authorName = state.getString(STATE_KEY_AUTHOR_NAME);
|
||||
password = state.getString(STATE_KEY_PASSWORD);
|
||||
} else if (state == SET_PASSWORD) {
|
||||
showPasswordFragment();
|
||||
} else if (state == DOZE) {
|
||||
showDozeFragment();
|
||||
} else if (state == CREATED || state == FAILED) {
|
||||
// TODO: Show an error if failed
|
||||
showApp();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectActivity(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
setupController.setSetupActivity(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle state) {
|
||||
super.onSaveInstanceState(state);
|
||||
if (authorName != null)
|
||||
state.putString(STATE_KEY_AUTHOR_NAME, authorName);
|
||||
if (password != null)
|
||||
state.putString(STATE_KEY_PASSWORD, password);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getAuthorName() {
|
||||
return authorName;
|
||||
}
|
||||
|
||||
void setAuthorName(String authorName) {
|
||||
this.authorName = authorName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
void showPasswordFragment() {
|
||||
if (authorName == null) throw new IllegalStateException();
|
||||
showNextFragment(SetPasswordFragment.newInstance());
|
||||
}
|
||||
|
||||
@TargetApi(23)
|
||||
void showDozeFragment() {
|
||||
if (authorName == null) throw new IllegalStateException();
|
||||
if (password == null) throw new IllegalStateException();
|
||||
showNextFragment(DozeFragment.newInstance());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
|
||||
@NotNullByDefault
|
||||
public interface SetupController {
|
||||
|
||||
void setSetupActivity(SetupActivity setupActivity);
|
||||
|
||||
boolean needToShowDozeFragment();
|
||||
|
||||
void setAuthorName(String authorName);
|
||||
|
||||
float estimatePasswordStrength(String password);
|
||||
|
||||
void setPassword(String password);
|
||||
|
||||
/**
|
||||
* This should be called after the author name has been set.
|
||||
*/
|
||||
void showPasswordFragment();
|
||||
|
||||
/**
|
||||
* This should be called after the author name and the password have been
|
||||
* set.
|
||||
*/
|
||||
void showDozeFragment();
|
||||
|
||||
/**
|
||||
* This should be called after the author name and the password have been
|
||||
* set.
|
||||
*/
|
||||
void createAccount();
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.briar.android.controller.handler.ResultHandler;
|
||||
import org.briarproject.briar.android.controller.handler.UiResultHandler;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@NotNullByDefault
|
||||
public class SetupControllerImpl implements SetupController {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(SetupControllerImpl.class.getName());
|
||||
|
||||
private final AccountManager accountManager;
|
||||
private final PasswordStrengthEstimator strengthEstimator;
|
||||
@IoExecutor
|
||||
private final Executor ioExecutor;
|
||||
@Nullable
|
||||
private volatile SetupActivity setupActivity;
|
||||
|
||||
@Inject
|
||||
SetupControllerImpl(AccountManager accountManager,
|
||||
@IoExecutor Executor ioExecutor,
|
||||
PasswordStrengthEstimator strengthEstimator) {
|
||||
this.accountManager = accountManager;
|
||||
this.strengthEstimator = strengthEstimator;
|
||||
this.ioExecutor = ioExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSetupActivity(SetupActivity setupActivity) {
|
||||
this.setupActivity = setupActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needToShowDozeFragment() {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
return DozeView.needsToBeShown(setupActivity) ||
|
||||
HuaweiView.needsToBeShown(setupActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthorName(String authorName) {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
setupActivity.setAuthorName(authorName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float estimatePasswordStrength(String password) {
|
||||
return strengthEstimator.estimateStrength(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPassword(String password) {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
setupActivity.setPassword(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPasswordFragment() {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
setupActivity.showPasswordFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showDozeFragment() {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
setupActivity.showDozeFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createAccount() {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
UiResultHandler<Boolean> resultHandler =
|
||||
new UiResultHandler<Boolean>(setupActivity) {
|
||||
@Override
|
||||
public void onResultUi(Boolean result) {
|
||||
// TODO: Show an error if result is false
|
||||
if (setupActivity == null)
|
||||
throw new IllegalStateException();
|
||||
setupActivity.showApp();
|
||||
}
|
||||
};
|
||||
createAccount(resultHandler);
|
||||
}
|
||||
|
||||
// Package access for testing
|
||||
void createAccount(ResultHandler<Boolean> resultHandler) {
|
||||
SetupActivity setupActivity = this.setupActivity;
|
||||
if (setupActivity == null) throw new IllegalStateException();
|
||||
String authorName = setupActivity.getAuthorName();
|
||||
if (authorName == null) throw new IllegalStateException();
|
||||
String password = setupActivity.getPassword();
|
||||
if (password == null) throw new IllegalStateException();
|
||||
ioExecutor.execute(() -> {
|
||||
LOG.info("Creating account");
|
||||
resultHandler.onResult(accountManager.createAccount(authorName,
|
||||
password));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
@@ -17,7 +19,10 @@ import org.briarproject.briar.android.fragment.BaseFragment;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
|
||||
import static android.view.inputmethod.EditorInfo.IME_ACTION_NEXT;
|
||||
@@ -29,8 +34,40 @@ import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
|
||||
abstract class SetupFragment extends BaseFragment implements TextWatcher,
|
||||
OnEditorActionListener, OnClickListener {
|
||||
|
||||
private final static String STATE_KEY_CLICKED = "setupFragmentClicked";
|
||||
private boolean clicked = false;
|
||||
|
||||
@Inject
|
||||
SetupController setupController;
|
||||
ViewModelProvider.Factory viewModelFactory;
|
||||
SetupViewModel viewModel;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
viewModel = new ViewModelProvider(requireActivity())
|
||||
.get(SetupViewModel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
if (savedInstanceState != null) {
|
||||
clicked = savedInstanceState.getBoolean(STATE_KEY_CLICKED);
|
||||
}
|
||||
if (clicked) {
|
||||
setNextClicked();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(STATE_KEY_CLICKED, clicked);
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
void setNextClicked() {
|
||||
this.clicked = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import org.briarproject.briar.android.viewmodel.ViewModelKey;
|
||||
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.multibindings.IntoMap;
|
||||
|
||||
@Module
|
||||
public abstract class SetupModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(SetupViewModel.class)
|
||||
abstract ViewModel bindSetupViewModel(
|
||||
SetupViewModel setupViewModel);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.AUTHOR_NAME;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.CREATED;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.DOZE;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.FAILED;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.SET_PASSWORD;
|
||||
|
||||
@MethodsNotNullByDefault
|
||||
@ParametersNotNullByDefault
|
||||
class SetupViewModel extends AndroidViewModel {
|
||||
enum State {AUTHOR_NAME, SET_PASSWORD, DOZE, CREATED, FAILED}
|
||||
|
||||
private static final Logger LOG =
|
||||
getLogger(SetupActivity.class.getName());
|
||||
|
||||
@Nullable
|
||||
private String authorName, password;
|
||||
private final MutableLiveEvent<State> state = new MutableLiveEvent<>();
|
||||
|
||||
private final AccountManager accountManager;
|
||||
private final Executor ioExecutor;
|
||||
private final PasswordStrengthEstimator strengthEstimator;
|
||||
private final DozeHelper dozeHelper;
|
||||
|
||||
@Inject
|
||||
SetupViewModel(Application app,
|
||||
AccountManager accountManager,
|
||||
@IoExecutor Executor ioExecutor,
|
||||
PasswordStrengthEstimator strengthEstimator,
|
||||
DozeHelper dozeHelper) {
|
||||
super(app);
|
||||
this.accountManager = accountManager;
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.strengthEstimator = strengthEstimator;
|
||||
this.dozeHelper = dozeHelper;
|
||||
|
||||
ioExecutor.execute(() -> {
|
||||
if (accountManager.accountExists()) {
|
||||
throw new AssertionError();
|
||||
} else {
|
||||
state.postEvent(AUTHOR_NAME);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
LiveEvent<State> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
void setAuthorName(String authorName) {
|
||||
this.authorName = authorName;
|
||||
state.setEvent(SET_PASSWORD);
|
||||
}
|
||||
|
||||
void setPassword(String password) {
|
||||
if (authorName == null) throw new IllegalStateException();
|
||||
this.password = password;
|
||||
if (needToShowDozeFragment()) {
|
||||
state.setEvent(DOZE);
|
||||
} else {
|
||||
createAccount();
|
||||
}
|
||||
}
|
||||
|
||||
float estimatePasswordStrength(String password) {
|
||||
return strengthEstimator.estimateStrength(password);
|
||||
}
|
||||
|
||||
boolean needToShowDozeFragment() {
|
||||
return dozeHelper.needToShowDozeFragment(getApplication());
|
||||
}
|
||||
|
||||
void dozeExceptionConfirmed() {
|
||||
createAccount();
|
||||
}
|
||||
|
||||
private void createAccount() {
|
||||
if (authorName == null) throw new IllegalStateException();
|
||||
if (password == null) throw new IllegalStateException();
|
||||
ioExecutor.execute(() -> {
|
||||
if (accountManager.createAccount(authorName, password)) {
|
||||
LOG.info("Created account");
|
||||
state.postEvent(CREATED);
|
||||
} else {
|
||||
LOG.warning("Failed to create account");
|
||||
state.postEvent(FAILED);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package org.briarproject.briar.android.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import org.briarproject.briar.android.account.SetupController;
|
||||
import org.briarproject.briar.android.account.SetupControllerImpl;
|
||||
import org.briarproject.briar.android.controller.BriarController;
|
||||
import org.briarproject.briar.android.controller.BriarControllerImpl;
|
||||
import org.briarproject.briar.android.controller.DbController;
|
||||
@@ -35,13 +33,6 @@ public class ActivityModule {
|
||||
return activity;
|
||||
}
|
||||
|
||||
@ActivityScope
|
||||
@Provides
|
||||
SetupController provideSetupController(
|
||||
SetupControllerImpl setupController) {
|
||||
return setupController;
|
||||
}
|
||||
|
||||
@ActivityScope
|
||||
@Provides
|
||||
protected BriarController provideBriarController(
|
||||
|
||||
@@ -34,6 +34,11 @@ public class LiveEvent<T> extends LiveData<LiveEvent.ConsumableEvent<T>> {
|
||||
super.observe(owner, observer);
|
||||
}
|
||||
|
||||
public void observeEventForever(LiveEventHandler<T> handler) {
|
||||
LiveEventObserver<T> observer = new LiveEventObserver<>(handler);
|
||||
super.observeForever(observer);
|
||||
}
|
||||
|
||||
static class ConsumableEvent<T> {
|
||||
|
||||
private final T content;
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.legacy.ClassImposteriser;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||
|
||||
public class SetupControllerImplTest extends BrambleMockTestCase {
|
||||
|
||||
private final AccountManager accountManager =
|
||||
context.mock(AccountManager.class);
|
||||
private final PasswordStrengthEstimator estimator =
|
||||
context.mock(PasswordStrengthEstimator.class);
|
||||
private final SetupActivity setupActivity;
|
||||
|
||||
private final Executor ioExecutor = new ImmediateExecutor();
|
||||
|
||||
private final String authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH);
|
||||
private final String password = getRandomString(10);
|
||||
|
||||
public SetupControllerImplTest() {
|
||||
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||
setupActivity = context.mock(SetupActivity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public void testCreateAccount() {
|
||||
context.checking(new Expectations() {{
|
||||
// Set the author name and password
|
||||
oneOf(setupActivity).setAuthorName(authorName);
|
||||
oneOf(setupActivity).setPassword(password);
|
||||
// Get the author name and password
|
||||
oneOf(setupActivity).getAuthorName();
|
||||
will(returnValue(authorName));
|
||||
oneOf(setupActivity).getPassword();
|
||||
will(returnValue(password));
|
||||
// Create the account
|
||||
oneOf(accountManager).createAccount(authorName, password);
|
||||
will(returnValue(true));
|
||||
}});
|
||||
|
||||
SetupControllerImpl s = new SetupControllerImpl(accountManager,
|
||||
ioExecutor, estimator);
|
||||
s.setSetupActivity(setupActivity);
|
||||
|
||||
AtomicBoolean called = new AtomicBoolean(false);
|
||||
s.setAuthorName(authorName);
|
||||
s.setPassword(password);
|
||||
s.createAccount(result -> called.set(true));
|
||||
assertTrue(called.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.briarproject.briar.android.account;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import org.briarproject.bramble.api.account.AccountManager;
|
||||
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
|
||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||
import org.briarproject.briar.android.account.SetupViewModel.State;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.lib.legacy.ClassImposteriser;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||
import static org.briarproject.briar.android.account.SetupViewModel.State.CREATED;
|
||||
import static org.briarproject.briar.android.viewmodel.LiveEventTestUtil.getOrAwaitValue;
|
||||
|
||||
public class SetupViewModelTest extends BrambleMockTestCase {
|
||||
|
||||
@Rule
|
||||
public final InstantTaskExecutorRule testRule =
|
||||
new InstantTaskExecutorRule();
|
||||
|
||||
private final String authorName = getRandomString(MAX_AUTHOR_NAME_LENGTH);
|
||||
private final String password = getRandomString(10);
|
||||
|
||||
private final Application app;
|
||||
private final Context appContext;
|
||||
private final AccountManager accountManager;
|
||||
private final DozeHelper dozeHelper;
|
||||
|
||||
public SetupViewModelTest() {
|
||||
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||
app = context.mock(Application.class);
|
||||
appContext = context.mock(Context.class);
|
||||
accountManager = context.mock(AccountManager.class);
|
||||
dozeHelper = context.mock(DozeHelper.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAccount() throws Exception {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(accountManager).accountExists();
|
||||
will(returnValue(false));
|
||||
allowing(dozeHelper).needToShowDozeFragment(app);
|
||||
allowing(app).getApplicationContext();
|
||||
will(returnValue(appContext));
|
||||
allowing(appContext).getPackageManager();
|
||||
|
||||
// Create the account
|
||||
oneOf(accountManager).createAccount(authorName, password);
|
||||
will(returnValue(true));
|
||||
}});
|
||||
|
||||
SetupViewModel viewModel = new SetupViewModel(app,
|
||||
accountManager,
|
||||
new ImmediateExecutor(),
|
||||
context.mock(PasswordStrengthEstimator.class),
|
||||
dozeHelper);
|
||||
|
||||
viewModel.setAuthorName(authorName);
|
||||
viewModel.setPassword(password);
|
||||
|
||||
State state = getOrAwaitValue(viewModel.getState());
|
||||
assertEquals(CREATED, state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* Copyright 2019 Google LLC.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
https://gist.github.com/JoseAlcerreca/1e9ee05dcdd6a6a6fa1cbfc125559bba
|
||||
*/
|
||||
|
||||
package org.briarproject.briar.android.viewmodel;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class LiveEventTestUtil {
|
||||
public static <T> T getOrAwaitValue(final LiveEvent<T> liveEvent)
|
||||
throws InterruptedException {
|
||||
final AtomicReference<T> data = new AtomicReference<>();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
liveEvent.observeEventForever(new LiveEvent.LiveEventHandler<T>() {
|
||||
@Override
|
||||
public void onEvent(T o) {
|
||||
data.set(o);
|
||||
latch.countDown();
|
||||
// LiveEventHandler is wrapped internally in an observer that we
|
||||
// don't have a reference to. Skip trying to remove the observer
|
||||
// for now; all is torn down at the end of testing anyway.
|
||||
}
|
||||
});
|
||||
|
||||
// Don't wait indefinitely if the LiveEvent is not set.
|
||||
if (!latch.await(2, TimeUnit.SECONDS)) {
|
||||
throw new RuntimeException("LiveEvent value was never set.");
|
||||
}
|
||||
return data.get();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user