diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml
index 51c5c7954..802d5cf8c 100644
--- a/briar-android/src/main/AndroidManifest.xml
+++ b/briar-android/src/main/AndroidManifest.xml
@@ -73,13 +73,13 @@
+ android:windowSoftInputMode="stateUnchanged">
@@ -94,11 +94,6 @@
-
-
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java
index 606a6ba72..6d502b4b9 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/BriarService.java
@@ -22,7 +22,6 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.R;
import org.briarproject.briar.android.logout.HideUiActivity;
-import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.api.android.AndroidNotificationManager;
import org.briarproject.briar.api.android.LockManager;
@@ -48,6 +47,7 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS;
+import static org.briarproject.briar.android.activity.ActivityComponent.ENTRY_ACTIVITY;
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_CHANNEL_ID;
import static org.briarproject.briar.api.android.AndroidNotificationManager.FAILURE_NOTIFICATION_ID;
import static org.briarproject.briar.api.android.AndroidNotificationManager.ONGOING_CHANNEL_ID;
@@ -182,7 +182,7 @@ public class BriarService extends Service {
NotificationManager nm = (NotificationManager) o;
nm.notify(FAILURE_NOTIFICATION_ID, b.build());
// Bring the dashboard to the front to clear the back stack
- i = new Intent(BriarService.this, NavDrawerActivity.class);
+ i = new Intent(BriarService.this, ENTRY_ACTIVITY);
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
i.putExtra(EXTRA_STARTUP_FAILED, true);
startActivity(i);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/AuthorNameFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/AuthorNameFragment.java
similarity index 98%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/AuthorNameFragment.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/AuthorNameFragment.java
index 109a9e153..8a9104d96 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/AuthorNameFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/AuthorNameFragment.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.os.Bundle;
import android.support.design.widget.TextInputEditText;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/DozeFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java
similarity index 96%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/DozeFragment.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java
index 2a180b3dc..7dd63ee4d 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/DozeFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeFragment.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.annotation.SuppressLint;
import android.content.Intent;
@@ -14,7 +14,7 @@ import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
-import org.briarproject.briar.android.login.PowerView.OnCheckedChangedListener;
+import org.briarproject.briar.android.account.PowerView.OnCheckedChangedListener;
import org.briarproject.briar.android.util.UiUtils;
import static android.view.View.INVISIBLE;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/DozeView.java b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeView.java
similarity index 96%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/DozeView.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/DozeView.java
index a2b1c5186..e02f4f2e5 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/DozeView.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/DozeView.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.content.Context;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/HuaweiView.java b/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiView.java
similarity index 97%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/HuaweiView.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiView.java
index c566ce697..2396aab25 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/HuaweiView.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/HuaweiView.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.content.Context;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PowerView.java b/briar-android/src/main/java/org/briarproject/briar/android/account/PowerView.java
similarity index 98%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/PowerView.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/PowerView.java
index ffcaf3409..032826ca5 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/PowerView.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/PowerView.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.content.Context;
import android.os.Parcel;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/account/SetPasswordFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetPasswordFragment.java
new file mode 100644
index 000000000..9895530d1
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetPasswordFragment.java
@@ -0,0 +1,130 @@
+package org.briarproject.briar.android.account;
+
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.design.widget.TextInputEditText;
+import android.support.design.widget.TextInputLayout;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.ProgressBar;
+
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.briar.R;
+import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.login.StrengthMeter;
+
+import javax.annotation.Nullable;
+
+import static android.content.Context.INPUT_METHOD_SERVICE;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
+import static java.util.Objects.requireNonNull;
+import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
+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;
+ private TextInputLayout passwordConfirmationWrapper;
+ private TextInputEditText passwordEntry;
+ private TextInputEditText passwordConfirmation;
+ private StrengthMeter strengthMeter;
+ private Button nextButton;
+ private ProgressBar progressBar;
+
+ public static SetPasswordFragment newInstance() {
+ return new SetPasswordFragment();
+ }
+
+ @Override
+ public void injectFragment(ActivityComponent component) {
+ component.inject(this);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ requireNonNull(getActivity()).setTitle(getString(R.string.setup_password_intro));
+ View v = inflater.inflate(R.layout.fragment_setup_password, container,
+ false);
+
+ strengthMeter = v.findViewById(R.id.strength_meter);
+ passwordEntryWrapper = v.findViewById(R.id.password_entry_wrapper);
+ passwordEntry = v.findViewById(R.id.password_entry);
+ passwordConfirmationWrapper =
+ v.findViewById(R.id.password_confirm_wrapper);
+ passwordConfirmation = v.findViewById(R.id.password_confirm);
+ nextButton = v.findViewById(R.id.next);
+ progressBar = v.findViewById(R.id.progress);
+
+ passwordEntry.addTextChangedListener(this);
+ passwordConfirmation.addTextChangedListener(this);
+ nextButton.setOnClickListener(this);
+
+ if (!setupController.needToShowDozeFragment()) {
+ nextButton.setText(R.string.create_account_button);
+ passwordConfirmation.setImeOptions(IME_ACTION_DONE);
+ }
+
+ return v;
+ }
+
+ @Override
+ public String getUniqueTag() {
+ return TAG;
+ }
+
+ @Override
+ protected String getHelpText() {
+ return getString(R.string.setup_password_explanation);
+ }
+
+ @Override
+ public void onTextChanged(CharSequence authorName, int i, int i1, int i2) {
+ String password1 = passwordEntry.getText().toString();
+ String password2 = passwordConfirmation.getText().toString();
+ boolean passwordsMatch = password1.equals(password2);
+
+ strengthMeter
+ .setVisibility(password1.length() > 0 ? VISIBLE : INVISIBLE);
+ float strength = setupController.estimatePasswordStrength(password1);
+ strengthMeter.setStrength(strength);
+ boolean strongEnough = strength >= QUITE_WEAK;
+
+ setError(passwordEntryWrapper, getString(R.string.password_too_weak),
+ password1.length() > 0 && !strongEnough);
+ setError(passwordConfirmationWrapper,
+ getString(R.string.passwords_do_not_match),
+ password2.length() > 0 && !passwordsMatch);
+
+ boolean enabled = passwordsMatch && strongEnough;
+ nextButton.setEnabled(enabled);
+ passwordConfirmation.setOnEditorActionListener(enabled ? this : null);
+ }
+
+ @Override
+ public void onClick(View view) {
+ 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();
+ }
+ }
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java
similarity index 87%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/SetupActivity.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java
index e38cfeb0c..dfa340597 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupActivity.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.annotation.TargetApi;
import android.content.Intent;
@@ -15,8 +15,11 @@ import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener
import javax.annotation.Nullable;
import javax.inject.Inject;
+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.activity.ActivityComponent.ENTRY_ACTIVITY;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
@@ -86,7 +89,7 @@ public class SetupActivity extends BaseActivity
void showPasswordFragment() {
if (authorName == null) throw new IllegalStateException();
- showNextFragment(PasswordFragment.newInstance());
+ showNextFragment(SetPasswordFragment.newInstance());
}
@TargetApi(23)
@@ -97,8 +100,9 @@ public class SetupActivity extends BaseActivity
}
void showApp() {
- Intent i = new Intent(this, OpenDatabaseActivity.class);
- i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
+ Intent i = new Intent(this, ENTRY_ACTIVITY);
+ i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME |
+ FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
supportFinishAfterTransition();
overridePendingTransition(R.anim.screen_new_in, R.anim.screen_old_out);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupController.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupController.java
similarity index 81%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/SetupController.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/SetupController.java
index 392151897..2a701f151 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupController.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupController.java
@@ -1,9 +1,9 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
-public interface SetupController extends PasswordController {
+public interface SetupController {
void setSetupActivity(SetupActivity setupActivity);
@@ -11,6 +11,8 @@ public interface SetupController extends PasswordController {
void setAuthorName(String authorName);
+ float estimatePasswordStrength(String password);
+
void setPassword(String password);
/**
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupControllerImpl.java
similarity index 86%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/SetupControllerImpl.java
index 02f40226e..89f88f622 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupControllerImpl.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.support.annotation.Nullable;
@@ -15,12 +15,15 @@ import java.util.logging.Logger;
import javax.inject.Inject;
@NotNullByDefault
-public class SetupControllerImpl extends PasswordControllerImpl
- implements SetupController {
+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;
@@ -28,7 +31,9 @@ public class SetupControllerImpl extends PasswordControllerImpl
SetupControllerImpl(AccountManager accountManager,
@IoExecutor Executor ioExecutor,
PasswordStrengthEstimator strengthEstimator) {
- super(accountManager, ioExecutor, strengthEstimator);
+ this.accountManager = accountManager;
+ this.strengthEstimator = strengthEstimator;
+ this.ioExecutor = ioExecutor;
}
@Override
@@ -51,6 +56,11 @@ public class SetupControllerImpl extends PasswordControllerImpl
setupActivity.setAuthorName(authorName);
}
+ @Override
+ public float estimatePasswordStrength(String password) {
+ return strengthEstimator.estimateStrength(password);
+ }
+
@Override
public void setPassword(String password) {
SetupActivity setupActivity = this.setupActivity;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupFragment.java
similarity index 97%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/SetupFragment.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/SetupFragment.java
index ba5da40de..acbcc8252 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/SetupFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/SetupFragment.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.support.annotation.Nullable;
import android.text.Editable;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/account/UnlockActivity.java
similarity index 99%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
rename to briar-android/src/main/java/org/briarproject/briar/android/account/UnlockActivity.java
index 2842ecb3e..cbbcf3d09 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/UnlockActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/account/UnlockActivity.java
@@ -1,4 +1,4 @@
-package org.briarproject.briar.android.login;
+package org.briarproject.briar.android.account;
import android.app.KeyguardManager;
import android.content.Intent;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
index 1c0e681ef..f87df6442 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
@@ -4,6 +4,11 @@ import android.app.Activity;
import org.briarproject.briar.android.AndroidComponent;
import org.briarproject.briar.android.StartupFailureActivity;
+import org.briarproject.briar.android.account.AuthorNameFragment;
+import org.briarproject.briar.android.account.DozeFragment;
+import org.briarproject.briar.android.account.SetPasswordFragment;
+import org.briarproject.briar.android.account.SetupActivity;
+import org.briarproject.briar.android.account.UnlockActivity;
import org.briarproject.briar.android.blog.BlogActivity;
import org.briarproject.briar.android.blog.BlogFragment;
import org.briarproject.briar.android.blog.BlogModule;
@@ -37,14 +42,10 @@ import org.briarproject.briar.android.keyagreement.ContactExchangeActivity;
import org.briarproject.briar.android.keyagreement.ContactExchangeErrorFragment;
import org.briarproject.briar.android.keyagreement.KeyAgreementActivity;
import org.briarproject.briar.android.keyagreement.KeyAgreementFragment;
-import org.briarproject.briar.android.login.AuthorNameFragment;
import org.briarproject.briar.android.login.ChangePasswordActivity;
-import org.briarproject.briar.android.login.DozeFragment;
-import org.briarproject.briar.android.login.OpenDatabaseActivity;
-import org.briarproject.briar.android.login.PasswordActivity;
+import org.briarproject.briar.android.login.OpenDatabaseFragment;
import org.briarproject.briar.android.login.PasswordFragment;
-import org.briarproject.briar.android.login.SetupActivity;
-import org.briarproject.briar.android.login.UnlockActivity;
+import org.briarproject.briar.android.login.StartupActivity;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
import org.briarproject.briar.android.panic.PanicResponderActivity;
@@ -90,18 +91,18 @@ import dagger.Component;
dependencies = AndroidComponent.class)
public interface ActivityComponent {
+ Class extends Activity> ENTRY_ACTIVITY = NavDrawerActivity.class;
+
Activity activity();
void inject(SplashScreenActivity activity);
+ void inject(StartupActivity activity);
+
void inject(SetupActivity activity);
- void inject(OpenDatabaseActivity activity);
-
void inject(NavDrawerActivity activity);
- void inject(PasswordActivity activity);
-
void inject(PanicResponderActivity activity);
void inject(PanicPreferencesActivity activity);
@@ -177,12 +178,17 @@ public interface ActivityComponent {
void inject(PendingContactListActivity activity);
// Fragments
+
void inject(AuthorNameFragment fragment);
- void inject(PasswordFragment fragment);
+ void inject(SetPasswordFragment fragment);
void inject(DozeFragment fragment);
+ void inject(PasswordFragment imageFragment);
+
+ void inject(OpenDatabaseFragment activity);
+
void inject(ContactListFragment fragment);
void inject(CreateGroupFragment fragment);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java
index b21d07232..52b8582f4 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java
@@ -6,10 +6,10 @@ import org.briarproject.briar.android.controller.BriarController;
import org.briarproject.briar.android.controller.BriarControllerImpl;
import org.briarproject.briar.android.controller.DbController;
import org.briarproject.briar.android.controller.DbControllerImpl;
-import org.briarproject.briar.android.login.PasswordController;
-import org.briarproject.briar.android.login.PasswordControllerImpl;
-import org.briarproject.briar.android.login.SetupController;
-import org.briarproject.briar.android.login.SetupControllerImpl;
+import org.briarproject.briar.android.login.ChangePasswordController;
+import org.briarproject.briar.android.login.ChangePasswordControllerImpl;
+import org.briarproject.briar.android.account.SetupController;
+import org.briarproject.briar.android.account.SetupControllerImpl;
import org.briarproject.briar.android.navdrawer.NavDrawerController;
import org.briarproject.briar.android.navdrawer.NavDrawerControllerImpl;
@@ -48,8 +48,8 @@ public class ActivityModule {
@ActivityScope
@Provides
- PasswordController providePasswordController(
- PasswordControllerImpl passwordController) {
+ ChangePasswordController providePasswordController(
+ ChangePasswordControllerImpl passwordController) {
return passwordController;
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java
index 917dce9b6..8f476d456 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BriarActivity.java
@@ -15,8 +15,8 @@ import org.briarproject.briar.R;
import org.briarproject.briar.android.controller.BriarController;
import org.briarproject.briar.android.controller.DbController;
import org.briarproject.briar.android.controller.handler.UiResultHandler;
-import org.briarproject.briar.android.login.PasswordActivity;
-import org.briarproject.briar.android.login.UnlockActivity;
+import org.briarproject.briar.android.login.StartupActivity;
+import org.briarproject.briar.android.account.UnlockActivity;
import org.briarproject.briar.android.logout.ExitActivity;
import org.briarproject.briar.api.android.LockManager;
@@ -86,8 +86,8 @@ public abstract class BriarActivity extends BaseActivity {
if (!briarController.accountSignedIn() && !isFinishing()) {
// Also check that the activity isn't finishing already.
// This is possible if we finished in onActivityResult().
- // Launching another PasswordActivity would cause a loop.
- Intent i = new Intent(this, PasswordActivity.class);
+ // Launching another StartupActivity would cause a loop.
+ Intent i = new Intent(this, StartupActivity.class);
startActivityForResult(i, REQUEST_PASSWORD);
} else if (lockManager.isLocked() && !isFinishing()) {
// Also check that the activity isn't finishing already.
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java
index d492f0472..7eb7a1bce 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/controller/BriarControllerImpl.java
@@ -8,6 +8,7 @@ import android.support.annotation.CallSuper;
import org.briarproject.bramble.api.account.AccountManager;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
+import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.briar.android.BriarService;
@@ -21,6 +22,7 @@ import java.util.logging.Logger;
import javax.inject.Inject;
import static java.util.logging.Level.WARNING;
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.briar.android.settings.SettingsFragment.SETTINGS_NAMESPACE;
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
@@ -34,6 +36,7 @@ public class BriarControllerImpl implements BriarController {
private final BriarServiceConnection serviceConnection;
private final AccountManager accountManager;
+ private final LifecycleManager lifecycleManager;
private final Executor databaseExecutor;
private final SettingsManager settingsManager;
private final DozeWatchdog dozeWatchdog;
@@ -44,11 +47,13 @@ public class BriarControllerImpl implements BriarController {
@Inject
BriarControllerImpl(BriarServiceConnection serviceConnection,
AccountManager accountManager,
+ LifecycleManager lifecycleManager,
@DatabaseExecutor Executor databaseExecutor,
SettingsManager settingsManager, DozeWatchdog dozeWatchdog,
Activity activity) {
this.serviceConnection = serviceConnection;
this.accountManager = accountManager;
+ this.lifecycleManager = lifecycleManager;
this.databaseExecutor = databaseExecutor;
this.settingsManager = settingsManager;
this.dozeWatchdog = dozeWatchdog;
@@ -84,7 +89,8 @@ public class BriarControllerImpl implements BriarController {
@Override
public boolean accountSignedIn() {
- return accountManager.hasDatabaseKey();
+ return accountManager.hasDatabaseKey() &&
+ lifecycleManager.getLifecycleState().isAfter(STARTING_SERVICES);
}
@Override
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordActivity.java
index 8a0604c1f..136e9e19d 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordActivity.java
@@ -31,7 +31,7 @@ public class ChangePasswordActivity extends BriarActivity
implements OnClickListener, OnEditorActionListener {
@Inject
- protected PasswordController passwordController;
+ protected ChangePasswordController passwordController;
private TextInputLayout currentPasswordEntryWrapper;
private TextInputLayout newPasswordEntryWrapper;
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java b/briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordController.java
similarity index 74%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java
rename to briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordController.java
index cef864152..54e8ab55d 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordController.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordController.java
@@ -4,13 +4,10 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.android.controller.handler.ResultHandler;
@NotNullByDefault
-public interface PasswordController {
+public interface ChangePasswordController {
float estimatePasswordStrength(String password);
- void validatePassword(String password,
- ResultHandler resultHandler);
-
void changePassword(String oldPassword, String newPassword,
ResultHandler resultHandler);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordControllerImpl.java
similarity index 79%
rename from briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java
rename to briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordControllerImpl.java
index 0ecf78475..79eaef917 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/ChangePasswordControllerImpl.java
@@ -11,14 +11,14 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
@NotNullByDefault
-public class PasswordControllerImpl implements PasswordController {
+public class ChangePasswordControllerImpl implements ChangePasswordController {
protected final AccountManager accountManager;
protected final Executor ioExecutor;
private final PasswordStrengthEstimator strengthEstimator;
@Inject
- PasswordControllerImpl(AccountManager accountManager,
+ ChangePasswordControllerImpl(AccountManager accountManager,
@IoExecutor Executor ioExecutor,
PasswordStrengthEstimator strengthEstimator) {
this.accountManager = accountManager;
@@ -31,13 +31,6 @@ public class PasswordControllerImpl implements PasswordController {
return strengthEstimator.estimateStrength(password);
}
- @Override
- public void validatePassword(String password,
- ResultHandler resultHandler) {
- ioExecutor.execute(() ->
- resultHandler.onResult(accountManager.signIn(password)));
- }
-
@Override
public void changePassword(String oldPassword, String newPassword,
ResultHandler resultHandler) {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseActivity.java
deleted file mode 100644
index 2f207d79c..000000000
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseActivity.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.briarproject.briar.android.login;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.briarproject.bramble.api.event.Event;
-import org.briarproject.bramble.api.event.EventBus;
-import org.briarproject.bramble.api.event.EventListener;
-import org.briarproject.bramble.api.lifecycle.LifecycleManager;
-import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState;
-import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
-import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
-import org.briarproject.briar.R;
-import org.briarproject.briar.android.activity.ActivityComponent;
-import org.briarproject.briar.android.activity.BriarActivity;
-import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
-
-import javax.inject.Inject;
-
-import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
-import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
-import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
-
-@ParametersNotNullByDefault
-public class OpenDatabaseActivity extends BriarActivity
- implements EventListener {
-
- @Inject
- LifecycleManager lifecycleManager;
- @Inject
- EventBus eventBus;
-
- private TextView textView;
- private ImageView imageView;
- private boolean showingMigration = false, showingCompaction = false;
-
- @Override
- public void onCreate(@Nullable Bundle state) {
- super.onCreate(state);
- setContentView(R.layout.activity_open_database);
- textView = findViewById(R.id.textView);
- imageView = findViewById(R.id.imageView);
- }
-
- @Override
- public void injectActivity(ActivityComponent component) {
- component.inject(this);
- }
-
- @Override
- public void onStart() {
- super.onStart();
- LifecycleState state = lifecycleManager.getLifecycleState();
- if (state.isAfter(STARTING_SERVICES)) {
- finishAndStartApp();
- } else {
- if (state == MIGRATING_DATABASE) showMigration();
- else if (state == COMPACTING_DATABASE) showCompaction();
- eventBus.addListener(this);
- }
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- eventBus.removeListener(this);
- }
-
- @Override
- public void eventOccurred(Event e) {
- if (e instanceof LifecycleEvent) {
- LifecycleState state = ((LifecycleEvent) e).getLifecycleState();
- if (state.isAfter(STARTING_SERVICES)) finishAndStartApp();
- else if (state == MIGRATING_DATABASE) showMigration();
- else if (state == COMPACTING_DATABASE) showCompaction();
- }
- }
-
- private void showMigration() {
- if (showingMigration) return;
- textView.setText(R.string.startup_migrate_database);
- imageView.setImageResource(R.drawable.startup_migration);
- showingMigration = true;
- }
-
- private void showCompaction() {
- if (showingCompaction) return;
- textView.setText(R.string.startup_compact_database);
- imageView.setImageResource(R.drawable.startup_migration);
- showingCompaction = true;
- }
-
- private void finishAndStartApp() {
- startActivity(new Intent(this, NavDrawerActivity.class));
- supportFinishAfterTransition();
- }
-
-}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseFragment.java
new file mode 100644
index 000000000..1a33b77f8
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/OpenDatabaseFragment.java
@@ -0,0 +1,78 @@
+package org.briarproject.briar.android.login;
+
+import android.arch.lifecycle.ViewModelProvider;
+import android.arch.lifecycle.ViewModelProviders;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.briar.R;
+import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.fragment.BaseFragment;
+
+import javax.inject.Inject;
+
+import static org.briarproject.briar.android.login.StartupViewModel.State;
+import static org.briarproject.briar.android.login.StartupViewModel.State.COMPACTING;
+import static org.briarproject.briar.android.login.StartupViewModel.State.MIGRATING;
+
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
+public class OpenDatabaseFragment extends BaseFragment {
+
+ final static String TAG = PasswordFragment.class.getName();
+
+ @Inject
+ ViewModelProvider.Factory viewModelFactory;
+
+ private TextView textView;
+ private ImageView imageView;
+
+ @Override
+ public void injectFragment(ActivityComponent component) {
+ component.inject(this);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View v = inflater.inflate(R.layout.fragment_open_database, container,
+ false);
+ textView = v.findViewById(R.id.textView);
+ imageView = v.findViewById(R.id.imageView);
+
+ StartupViewModel viewModel = ViewModelProviders.of(requireActivity(),
+ viewModelFactory).get(StartupViewModel.class);
+ viewModel.getState().observe(this, this::onStateChanged);
+
+ return v;
+ }
+
+ private void onStateChanged(State state) {
+ if (state == MIGRATING) showMigration();
+ else if (state == COMPACTING) showCompaction();
+ }
+
+ private void showMigration() {
+ textView.setText(R.string.startup_migrate_database);
+ imageView.setImageResource(R.drawable.startup_migration);
+ }
+
+ private void showCompaction() {
+ textView.setText(R.string.startup_compact_database);
+ imageView.setImageResource(R.drawable.startup_migration);
+ }
+
+ @Override
+ public String getUniqueTag() {
+ return TAG;
+ }
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java
deleted file mode 100644
index e8b20f243..000000000
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordActivity.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.briarproject.briar.android.login;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.design.widget.TextInputLayout;
-import android.support.v7.app.AlertDialog;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ProgressBar;
-
-import org.briarproject.bramble.api.account.AccountManager;
-import org.briarproject.briar.R;
-import org.briarproject.briar.android.activity.ActivityComponent;
-import org.briarproject.briar.android.activity.BaseActivity;
-import org.briarproject.briar.android.controller.BriarController;
-import org.briarproject.briar.android.controller.handler.UiResultHandler;
-import org.briarproject.briar.android.util.UiUtils;
-import org.briarproject.briar.api.android.AndroidNotificationManager;
-
-import javax.inject.Inject;
-
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
-import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
-import static org.briarproject.briar.android.util.UiUtils.enterPressed;
-
-public class PasswordActivity extends BaseActivity {
-
- @Inject
- AccountManager accountManager;
-
- @Inject
- AndroidNotificationManager notificationManager;
-
- @Inject
- PasswordController passwordController;
-
- @Inject
- BriarController briarController;
-
- private Button signInButton;
- private ProgressBar progress;
- private TextInputLayout input;
- private EditText password;
-
- @Override
- public void onCreate(Bundle state) {
- super.onCreate(state);
- // fade-in after splash screen instead of default animation
- overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
-
- if (!accountManager.accountExists()) {
- setResult(RESULT_CANCELED);
- finish();
- return;
- }
-
- setContentView(R.layout.activity_password);
- signInButton = findViewById(R.id.btn_sign_in);
- progress = findViewById(R.id.progress_wheel);
- input = findViewById(R.id.password_layout);
- password = findViewById(R.id.edit_password);
- password.setOnEditorActionListener((v, actionId, event) -> {
- if (actionId == IME_ACTION_DONE || enterPressed(actionId, event)) {
- validatePassword();
- return true;
- }
- return false;
- });
- password.addTextChangedListener(new TextWatcher() {
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before,
- int count) {
- if (count > 0) UiUtils.setError(input, null, false);
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- }
- });
- }
-
- @Override
- public void onStart() {
- super.onStart();
- // If the user has already signed in, clean up this instance
- if (briarController.accountSignedIn()) {
- setResult(RESULT_OK);
- finish();
- } else {
- notificationManager.blockSignInNotification();
- notificationManager.clearSignInNotification();
- }
- }
-
- @Override
- public void injectActivity(ActivityComponent component) {
- component.inject(this);
- }
-
- @Override
- public void onBackPressed() {
- // Move task and activity to the background instead of showing another
- // password prompt. onActivityResult() won't be called in BriarActivity
- moveTaskToBack(true);
- }
-
- private void deleteAccount() {
- accountManager.deleteAccount();
- startActivity(new Intent(this, SetupActivity.class));
- setResult(RESULT_CANCELED);
- finish();
- }
-
- public void onSignInClick(View v) {
- validatePassword();
- }
-
- public void onForgottenPasswordClick(View v) {
- // TODO Encapsulate the dialog in a re-usable fragment
- AlertDialog.Builder builder = new AlertDialog.Builder(this,
- R.style.BriarDialogTheme);
- builder.setTitle(R.string.dialog_title_lost_password);
- builder.setMessage(R.string.dialog_message_lost_password);
- builder.setPositiveButton(R.string.cancel, null);
- builder.setNegativeButton(R.string.delete,
- (dialog, which) -> deleteAccount());
- AlertDialog dialog = builder.create();
- dialog.show();
- }
-
- private void validatePassword() {
- hideSoftKeyboard(password);
- signInButton.setVisibility(INVISIBLE);
- progress.setVisibility(VISIBLE);
- passwordController.validatePassword(password.getText().toString(),
- new UiResultHandler(this) {
- @Override
- public void onResultUi(@NonNull Boolean result) {
- if (result) {
- setResult(RESULT_OK);
- supportFinishAfterTransition();
- // don't show closing animation,
- // but one for opening NavDrawerActivity
- overridePendingTransition(R.anim.screen_new_in,
- R.anim.screen_old_out);
- } else {
- tryAgain();
- }
- }
- });
- }
-
- private void tryAgain() {
- UiUtils.setError(input, getString(R.string.try_again), true);
- signInButton.setVisibility(VISIBLE);
- progress.setVisibility(INVISIBLE);
- password.setText("");
-
- // show the keyboard again
- showSoftKeyboard(password);
- }
-}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java
index 29950050f..d83421ad2 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/PasswordFragment.java
@@ -1,48 +1,50 @@
package org.briarproject.briar.android.login;
+import android.arch.lifecycle.ViewModelProvider;
+import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
-import android.os.IBinder;
-import android.support.design.widget.TextInputEditText;
import android.support.design.widget.TextInputLayout;
+import android.support.v7.app.AlertDialog;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
+import android.widget.EditText;
import android.widget.ProgressBar;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
-import org.briarproject.briar.android.util.UiUtils;
+import org.briarproject.briar.android.fragment.BaseFragment;
import javax.annotation.Nullable;
+import javax.inject.Inject;
-import static android.content.Context.INPUT_METHOD_SERVICE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
-import static java.util.Objects.requireNonNull;
-import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
+import static org.briarproject.briar.android.util.UiUtils.enterPressed;
+import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
+import static org.briarproject.briar.android.util.UiUtils.setError;
+import static org.briarproject.briar.android.util.UiUtils.showSoftKeyboard;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
-public class PasswordFragment extends SetupFragment {
+public class PasswordFragment extends BaseFragment implements TextWatcher {
private final static String TAG = PasswordFragment.class.getName();
- private TextInputLayout passwordEntryWrapper;
- private TextInputLayout passwordConfirmationWrapper;
- private TextInputEditText passwordEntry;
- private TextInputEditText passwordConfirmation;
- private StrengthMeter strengthMeter;
- private Button nextButton;
- private ProgressBar progressBar;
+ @Inject
+ ViewModelProvider.Factory viewModelFactory;
- public static PasswordFragment newInstance() {
- return new PasswordFragment();
- }
+ private StartupViewModel viewModel;
+ private Button signInButton;
+ private ProgressBar progress;
+ private TextInputLayout input;
+ private EditText password;
@Override
public void injectFragment(ActivityComponent component) {
@@ -53,78 +55,85 @@ public class PasswordFragment extends SetupFragment {
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
- requireNonNull(getActivity()).setTitle(getString(R.string.setup_password_intro));
- View v = inflater.inflate(R.layout.fragment_setup_password, container,
+ View v = inflater.inflate(R.layout.fragment_password, container,
false);
- strengthMeter = v.findViewById(R.id.strength_meter);
- passwordEntryWrapper = v.findViewById(R.id.password_entry_wrapper);
- passwordEntry = v.findViewById(R.id.password_entry);
- passwordConfirmationWrapper =
- v.findViewById(R.id.password_confirm_wrapper);
- passwordConfirmation = v.findViewById(R.id.password_confirm);
- nextButton = v.findViewById(R.id.next);
- progressBar = v.findViewById(R.id.progress);
+ viewModel = ViewModelProviders.of(requireActivity(), viewModelFactory)
+ .get(StartupViewModel.class);
+ viewModel.getPasswordValidated().observe(this, this::onPasswordValidated);
- passwordEntry.addTextChangedListener(this);
- passwordConfirmation.addTextChangedListener(this);
- nextButton.setOnClickListener(this);
-
- if (!setupController.needToShowDozeFragment()) {
- nextButton.setText(R.string.create_account_button);
- passwordConfirmation.setImeOptions(IME_ACTION_DONE);
- }
+ signInButton = v.findViewById(R.id.btn_sign_in);
+ signInButton.setOnClickListener(view -> onSignInButtonClicked());
+ progress = v.findViewById(R.id.progress_wheel);
+ input = v.findViewById(R.id.password_layout);
+ password = v.findViewById(R.id.edit_password);
+ password.setOnEditorActionListener((view, actionId, event) -> {
+ if (actionId == IME_ACTION_DONE || enterPressed(actionId, event)) {
+ onSignInButtonClicked();
+ return true;
+ }
+ return false;
+ });
+ password.addTextChangedListener(this);
+ v.findViewById(R.id.btn_forgotten)
+ .setOnClickListener(view -> onForgottenPasswordClick());
return v;
}
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before,
+ int count) {
+ if (count > 0) setError(input, null, false);
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+
+ private void onSignInButtonClicked() {
+ hideSoftKeyboard(password);
+ signInButton.setVisibility(INVISIBLE);
+ progress.setVisibility(VISIBLE);
+ viewModel.validatePassword(password.getText().toString());
+ }
+
+ private void onPasswordValidated(@Nullable Boolean valid) {
+ if (valid != null && !valid) {
+ setError(input, getString(R.string.try_again), true);
+ signInButton.setVisibility(VISIBLE);
+ progress.setVisibility(INVISIBLE);
+ password.setText(null);
+
+ // show the keyboard again
+ showSoftKeyboard(password);
+
+ // reset validation state for configuration changes
+ viewModel.getPasswordValidated().setValue(null);
+ }
+ }
+
+ public void onForgottenPasswordClick() {
+ // TODO Encapsulate the dialog in a re-usable fragment
+ AlertDialog.Builder builder = new AlertDialog.Builder(requireContext(),
+ R.style.BriarDialogTheme);
+ builder.setTitle(R.string.dialog_title_lost_password);
+ builder.setMessage(R.string.dialog_message_lost_password);
+ builder.setPositiveButton(R.string.cancel, null);
+ builder.setNegativeButton(R.string.delete,
+ (dialog, which) -> viewModel.deleteAccount());
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
@Override
public String getUniqueTag() {
return TAG;
}
- @Override
- protected String getHelpText() {
- return getString(R.string.setup_password_explanation);
- }
-
- @Override
- public void onTextChanged(CharSequence authorName, int i, int i1, int i2) {
- String password1 = passwordEntry.getText().toString();
- String password2 = passwordConfirmation.getText().toString();
- boolean passwordsMatch = password1.equals(password2);
-
- strengthMeter
- .setVisibility(password1.length() > 0 ? VISIBLE : INVISIBLE);
- float strength = setupController.estimatePasswordStrength(password1);
- strengthMeter.setStrength(strength);
- boolean strongEnough = strength >= QUITE_WEAK;
-
- UiUtils.setError(passwordEntryWrapper,
- getString(R.string.password_too_weak),
- password1.length() > 0 && !strongEnough);
- UiUtils.setError(passwordConfirmationWrapper,
- getString(R.string.passwords_do_not_match),
- password2.length() > 0 && !passwordsMatch);
-
- boolean enabled = passwordsMatch && strongEnough;
- nextButton.setEnabled(enabled);
- passwordConfirmation.setOnEditorActionListener(enabled ? this : null);
- }
-
- @Override
- public void onClick(View view) {
- 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();
- }
- }
-
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java
new file mode 100644
index 000000000..6b29c74a7
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/StartupActivity.java
@@ -0,0 +1,120 @@
+package org.briarproject.briar.android.login;
+
+import android.arch.lifecycle.ViewModelProvider;
+import android.arch.lifecycle.ViewModelProviders;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.briar.R;
+import org.briarproject.briar.android.BriarService;
+import org.briarproject.briar.android.account.SetupActivity;
+import org.briarproject.briar.android.activity.ActivityComponent;
+import org.briarproject.briar.android.activity.BaseActivity;
+import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
+import org.briarproject.briar.android.login.StartupViewModel.State;
+
+import javax.inject.Inject;
+
+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 org.briarproject.briar.android.login.StartupViewModel.State.SIGNED_IN;
+import static org.briarproject.briar.android.login.StartupViewModel.State.SIGNED_OUT;
+import static org.briarproject.briar.android.login.StartupViewModel.State.STARTED;
+import static org.briarproject.briar.android.login.StartupViewModel.State.STARTING;
+
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
+public class StartupActivity extends BaseActivity implements
+ BaseFragmentListener {
+
+ @Inject
+ ViewModelProvider.Factory viewModelFactory;
+
+ private StartupViewModel viewModel;
+
+ @Override
+ public void injectActivity(ActivityComponent component) {
+ component.inject(this);
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle state) {
+ super.onCreate(state);
+ // fade-in after splash screen instead of default animation
+ overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
+
+ setContentView(R.layout.activity_fragment_container);
+
+ viewModel = ViewModelProviders.of(this, viewModelFactory)
+ .get(StartupViewModel.class);
+ if (!viewModel.accountExists()) {
+ // TODO ideally we would not have to delete the account again
+ // The account needs to deleted again to remove the database folder,
+ // because if it exists, we assume the database also exists
+ // and when clearing app data, the folder does not get deleted.
+ viewModel.deleteAccount();
+ onAccountDeleted(true);
+ return;
+ }
+ viewModel.getAccountDeleted().observe(this, this::onAccountDeleted);
+ viewModel.getState().observe(this, this::onStateChanged);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ viewModel.clearSignInNotification();
+ }
+
+ @Override
+ public void onBackPressed() {
+ // Move task and activity to the background instead of showing another
+ // password prompt.
+ // onActivityResult() won't be called in BriarActivity
+ moveTaskToBack(true);
+ }
+
+ private void onStateChanged(State state) {
+ if (state == SIGNED_OUT) {
+ showInitialFragment(new PasswordFragment());
+ } else if (state == SIGNED_IN) {
+ startService(new Intent(this, BriarService.class));
+ } else if (state == STARTING) {
+ // only show OpenDatabaseFragment if not already visible
+ FragmentManager fm = getSupportFragmentManager();
+ Fragment f = fm.findFragmentByTag(OpenDatabaseFragment.TAG);
+ if (f == null || !f.isVisible()) {
+ showNextFragment(new OpenDatabaseFragment());
+ }
+ } else if (state == STARTED) {
+ setResult(RESULT_OK);
+ supportFinishAfterTransition();
+ overridePendingTransition(R.anim.screen_new_in,
+ R.anim.screen_old_out);
+ }
+ }
+
+ private void onAccountDeleted(boolean accountDeleted) {
+ if (accountDeleted) {
+ setResult(RESULT_CANCELED);
+ finish();
+ Intent i = new Intent(this, SetupActivity.class);
+ i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP |
+ FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(i);
+ }
+ }
+
+ @Override
+ public void runOnDbThread(Runnable runnable) {
+ // we don't need this and shouldn't be forced to implement it
+ throw new AssertionError();
+ }
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/login/StartupViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/login/StartupViewModel.java
new file mode 100644
index 000000000..a152c863b
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/login/StartupViewModel.java
@@ -0,0 +1,129 @@
+package org.briarproject.briar.android.login;
+
+import android.app.Application;
+import android.arch.lifecycle.AndroidViewModel;
+import android.arch.lifecycle.LiveData;
+import android.arch.lifecycle.MutableLiveData;
+import android.support.annotation.UiThread;
+
+import org.briarproject.bramble.api.account.AccountManager;
+import org.briarproject.bramble.api.event.Event;
+import org.briarproject.bramble.api.event.EventBus;
+import org.briarproject.bramble.api.event.EventListener;
+import org.briarproject.bramble.api.lifecycle.IoExecutor;
+import org.briarproject.bramble.api.lifecycle.LifecycleManager;
+import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState;
+import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent;
+import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
+import org.briarproject.briar.api.android.AndroidNotificationManager;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
+import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
+import static org.briarproject.briar.android.login.StartupViewModel.State.COMPACTING;
+import static org.briarproject.briar.android.login.StartupViewModel.State.MIGRATING;
+import static org.briarproject.briar.android.login.StartupViewModel.State.SIGNED_IN;
+import static org.briarproject.briar.android.login.StartupViewModel.State.SIGNED_OUT;
+import static org.briarproject.briar.android.login.StartupViewModel.State.STARTED;
+import static org.briarproject.briar.android.login.StartupViewModel.State.STARTING;
+
+@NotNullByDefault
+public class StartupViewModel extends AndroidViewModel
+ implements EventListener {
+
+ enum State {SIGNED_OUT, SIGNED_IN, STARTING, MIGRATING, COMPACTING, STARTED}
+
+ private final AccountManager accountManager;
+ private final AndroidNotificationManager notificationManager;
+ private final EventBus eventBus;
+ @IoExecutor
+ private final Executor ioExecutor;
+
+ private final MutableLiveData passwordValidated =
+ new MutableLiveData<>();
+ private final MutableLiveData accountDeleted =
+ new MutableLiveData<>();
+ private final MutableLiveData state = new MutableLiveData<>();
+
+ @Inject
+ StartupViewModel(Application app,
+ AccountManager accountManager,
+ LifecycleManager lifecycleManager,
+ AndroidNotificationManager notificationManager,
+ EventBus eventBus,
+ @IoExecutor Executor ioExecutor) {
+ super(app);
+ this.accountManager = accountManager;
+ this.notificationManager = notificationManager;
+ this.eventBus = eventBus;
+ this.ioExecutor = ioExecutor;
+
+ updateState(lifecycleManager.getLifecycleState());
+ eventBus.addListener(this);
+ }
+
+ @Override
+ protected void onCleared() {
+ eventBus.removeListener(this);
+ }
+
+ @Override
+ public void eventOccurred(Event e) {
+ if (e instanceof LifecycleEvent) {
+ LifecycleState s = ((LifecycleEvent) e).getLifecycleState();
+ updateState(s);
+ }
+ }
+
+ @UiThread
+ private void updateState(LifecycleState s) {
+ if (accountManager.hasDatabaseKey()) {
+ if (s.isAfter(STARTING_SERVICES)) state.setValue(STARTED);
+ else if (s == MIGRATING_DATABASE) state.setValue(MIGRATING);
+ else if (s == COMPACTING_DATABASE) state.setValue(COMPACTING);
+ else state.setValue(STARTING);
+ } else {
+ state.setValue(SIGNED_OUT);
+ }
+ }
+
+ boolean accountExists() {
+ return accountManager.accountExists();
+ }
+
+ void clearSignInNotification() {
+ notificationManager.blockSignInNotification();
+ notificationManager.clearSignInNotification();
+ }
+
+ void validatePassword(String password) {
+ ioExecutor.execute(() -> {
+ boolean signedIn = accountManager.signIn(password);
+ passwordValidated.postValue(signedIn);
+ if (signedIn) state.postValue(SIGNED_IN);
+ });
+ }
+
+ MutableLiveData getPasswordValidated() {
+ return passwordValidated;
+ }
+
+ LiveData getAccountDeleted() {
+ return accountDeleted;
+ }
+
+ LiveData getState() {
+ return state;
+ }
+
+ @UiThread
+ void deleteAccount() {
+ accountManager.deleteAccount();
+ accountDeleted.setValue(true);
+ }
+
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
index b8e46d569..85bb7b2b1 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/settings/SettingsFragment.java
@@ -40,7 +40,6 @@ import org.briarproject.bramble.plugin.tor.CircumventionProvider;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import org.briarproject.briar.android.Localizer;
-import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.util.UiUtils;
import java.util.ArrayList;
@@ -80,6 +79,7 @@ import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now;
import static org.briarproject.briar.android.TestingConstants.IS_DEBUG_BUILD;
+import static org.briarproject.briar.android.activity.ActivityComponent.ENTRY_ACTIVITY;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_RINGTONE;
import static org.briarproject.briar.android.navdrawer.NavDrawerActivity.INTENT_SIGN_OUT;
import static org.briarproject.briar.android.util.UiUtils.hasScreenLock;
@@ -192,7 +192,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
// bring up parent activity, so it can change its theme as well
// upstream bug: https://issuetracker.google.com/issues/38352704
Intent intent =
- new Intent(getActivity(), NavDrawerActivity.class);
+ new Intent(getActivity(), ENTRY_ACTIVITY);
intent.setFlags(
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
@@ -575,8 +575,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
builder.setPositiveButton(R.string.sign_out_button,
(dialogInterface, i) -> {
language.setValue(newValue);
- Intent intent = new Intent(getContext(),
- NavDrawerActivity.class);
+ Intent intent = new Intent(getContext(), ENTRY_ACTIVITY);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(INTENT_SIGN_OUT, true);
requireActivity().startActivity(intent);
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java
index 5b80d3cc3..b3030e52e 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java
@@ -2,10 +2,8 @@ package org.briarproject.briar.android.splash;
import android.app.Activity;
import android.content.Intent;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.support.v7.preference.PreferenceManager;
import android.transition.Fade;
import org.briarproject.bramble.api.account.AccountManager;
@@ -15,10 +13,6 @@ import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BaseActivity;
-import org.briarproject.briar.android.login.OpenDatabaseActivity;
-import org.briarproject.briar.android.login.SetupActivity;
-import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
-import org.briarproject.briar.api.android.LockManager;
import java.util.logging.Logger;
@@ -27,27 +21,35 @@ import javax.inject.Inject;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.os.Build.VERSION.SDK_INT;
+import static android.support.v7.preference.PreferenceManager.setDefaultValues;
+import static java.lang.System.currentTimeMillis;
+import static java.util.logging.Logger.getLogger;
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
+import static org.briarproject.briar.android.activity.ActivityComponent.ENTRY_ACTIVITY;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class SplashScreenActivity extends BaseActivity {
private static final Logger LOG =
- Logger.getLogger(SplashScreenActivity.class.getName());
+ getLogger(SplashScreenActivity.class.getName());
@Inject
protected AccountManager accountManager;
@Inject
- protected LockManager lockManager;
- @Inject
protected AndroidExecutor androidExecutor;
+ @Override
+ public void injectActivity(ActivityComponent component) {
+ component.inject(this);
+ }
+
@Override
public void onCreate(@Nullable Bundle state) {
super.onCreate(state);
- if (Build.VERSION.SDK_INT >= 21) {
+ if (SDK_INT >= 21) {
getWindow().setExitTransition(new Fade());
}
@@ -56,44 +58,21 @@ public class SplashScreenActivity extends BaseActivity {
setContentView(R.layout.splash);
if (accountManager.hasDatabaseKey()) {
- if (lockManager.isLocked()) {
- // The database needs to be opened for the app to be locked.
- // Start main activity right away. It will open UnlockActivity.
- // Otherwise, we would end up with two screen unlock inputs.
- startNextActivity(NavDrawerActivity.class);
- } else {
- startNextActivity(OpenDatabaseActivity.class);
- }
+ startNextActivity(ENTRY_ACTIVITY);
finish();
} else {
new Handler().postDelayed(() -> {
- startNextActivity();
+ if (currentTimeMillis() >= EXPIRY_DATE) {
+ LOG.info("Expired");
+ startNextActivity(ExpiredActivity.class);
+ } else {
+ startNextActivity(ENTRY_ACTIVITY);
+ }
supportFinishAfterTransition();
}, 500);
}
}
- @Override
- public void injectActivity(ActivityComponent component) {
- component.inject(this);
- }
-
- private void startNextActivity() {
- if (System.currentTimeMillis() >= EXPIRY_DATE) {
- LOG.info("Expired");
- startNextActivity(ExpiredActivity.class);
- } else {
- if (accountManager.accountExists()) {
- LOG.info("Account exists");
- startNextActivity(OpenDatabaseActivity.class);
- } else {
- LOG.info("Account does not exist");
- accountManager.deleteAccount();
- startNextActivity(SetupActivity.class);
- }
- }
- }
-
private void startNextActivity(Class extends Activity> activityClass) {
Intent i = new Intent(this, activityClass);
i.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
@@ -101,8 +80,8 @@ public class SplashScreenActivity extends BaseActivity {
}
private void setPreferencesDefaults() {
- androidExecutor.runOnBackgroundThread(() ->
- PreferenceManager.setDefaultValues(SplashScreenActivity.this,
+ androidExecutor.runOnBackgroundThread(
+ () -> setDefaultValues(SplashScreenActivity.this,
R.xml.panic_preferences, false));
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/test/TestDataActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/test/TestDataActivity.java
index fad48f249..7e7eb8024 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/test/TestDataActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/test/TestDataActivity.java
@@ -11,12 +11,12 @@ import android.widget.TextView;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity;
-import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.api.test.TestDataCreator;
import javax.inject.Inject;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static org.briarproject.briar.android.activity.ActivityComponent.ENTRY_ACTIVITY;
public class TestDataActivity extends BriarActivity {
@@ -154,7 +154,7 @@ public class TestDataActivity extends BriarActivity {
testDataCreator.createTestData(contactsSeekBar.getProgress() + 1,
messagesSeekBar.getProgress(), blogPostsSeekBar.getProgress(),
forumsSeekBar.getProgress(), forumPostsSeekBar.getProgress());
- Intent intent = new Intent(this, NavDrawerActivity.class);
+ Intent intent = new Intent(this, ENTRY_ACTIVITY);
intent.addFlags(FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
index eb7ecd9af..fd42e26bd 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
@@ -36,6 +36,7 @@ import android.transition.Transition;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.View;
+import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;
import org.acra.ACRA;
@@ -56,6 +57,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.Build.MANUFACTURER;
import static android.os.Build.VERSION.SDK_INT;
import static android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS;
+import static android.support.v4.content.ContextCompat.getSystemService;
import static android.support.v4.view.ViewCompat.LAYOUT_DIRECTION_RTL;
import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_AUTO;
import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
@@ -76,6 +78,8 @@ import static android.text.format.DateUtils.YEAR_IN_MILLIS;
import static android.view.KeyEvent.ACTION_DOWN;
import static android.view.KeyEvent.KEYCODE_ENTER;
import static android.view.inputmethod.EditorInfo.IME_NULL;
+import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
+import static java.util.Objects.requireNonNull;
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
import static org.briarproject.briar.android.TestingConstants.EXPIRY_DATE;
@@ -87,6 +91,18 @@ public class UiUtils {
public static final int TEASER_LENGTH = 320;
public static final float GREY_OUT = 0.5f;
+ public static void showSoftKeyboard(View view) {
+ InputMethodManager imm = requireNonNull(
+ getSystemService(view.getContext(), InputMethodManager.class));
+ imm.showSoftInput(view, SHOW_IMPLICIT);
+ }
+
+ public static void hideSoftKeyboard(View view) {
+ InputMethodManager imm = requireNonNull(
+ getSystemService(view.getContext(), InputMethodManager.class));
+ imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
+ }
+
public static String getContactDisplayName(Author author,
@Nullable String alias) {
String name = author.getName();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/viewmodel/ViewModelModule.java b/briar-android/src/main/java/org/briarproject/briar/android/viewmodel/ViewModelModule.java
index d35f2bb5b..86864b692 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/viewmodel/ViewModelModule.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/viewmodel/ViewModelModule.java
@@ -7,6 +7,7 @@ import org.briarproject.briar.android.contact.add.remote.AddContactViewModel;
import org.briarproject.briar.android.contact.add.remote.PendingContactListViewModel;
import org.briarproject.briar.android.conversation.ConversationViewModel;
import org.briarproject.briar.android.conversation.ImageViewModel;
+import org.briarproject.briar.android.login.StartupViewModel;
import javax.inject.Singleton;
@@ -17,6 +18,11 @@ import dagger.multibindings.IntoMap;
@Module
public abstract class ViewModelModule {
+ @Binds
+ @IntoMap
+ @ViewModelKey(StartupViewModel.class)
+ abstract ViewModel bindStartupViewModel(StartupViewModel startupViewModel);
+
@Binds
@IntoMap
@ViewModelKey(ConversationViewModel.class)
diff --git a/briar-android/src/main/res/layout/activity_unlock.xml b/briar-android/src/main/res/layout/activity_unlock.xml
index 83c8d594b..4a157595a 100644
--- a/briar-android/src/main/res/layout/activity_unlock.xml
+++ b/briar-android/src/main/res/layout/activity_unlock.xml
@@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- tools:context=".android.login.UnlockActivity">
+ tools:context=".android.account.UnlockActivity">
+ android:layout_height="match_parent"
+ tools:context=".android.login.PasswordFragment">
-
-
- > resultCaptor;
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java b/briar-android/src/test/java/org/briarproject/briar/android/login/ChangePasswordControllerImplTest.java
similarity index 87%
rename from briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java
rename to briar-android/src/test/java/org/briarproject/briar/android/login/ChangePasswordControllerImplTest.java
index 987155ffc..a588cb71b 100644
--- a/briar-android/src/test/java/org/briarproject/briar/android/login/PasswordControllerImplTest.java
+++ b/briar-android/src/test/java/org/briarproject/briar/android/login/ChangePasswordControllerImplTest.java
@@ -14,7 +14,7 @@ import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.briarproject.bramble.util.StringUtils.getRandomString;
-public class PasswordControllerImplTest extends BrambleMockTestCase {
+public class ChangePasswordControllerImplTest extends BrambleMockTestCase {
private final AccountManager accountManager =
context.mock(AccountManager.class);
@@ -33,7 +33,7 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
will(returnValue(true));
}});
- PasswordControllerImpl p = new PasswordControllerImpl(accountManager,
+ ChangePasswordControllerImpl p = new ChangePasswordControllerImpl(accountManager,
ioExecutor, estimator);
AtomicBoolean capturedResult = new AtomicBoolean(false);
@@ -48,7 +48,7 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
will(returnValue(false));
}});
- PasswordControllerImpl p = new PasswordControllerImpl(accountManager,
+ ChangePasswordControllerImpl p = new ChangePasswordControllerImpl(accountManager,
ioExecutor, estimator);
AtomicBoolean capturedResult = new AtomicBoolean(true);
diff --git a/briar-android/src/test/java/org/briarproject/briar/android/login/TestChangePasswordActivity.java b/briar-android/src/test/java/org/briarproject/briar/android/login/TestChangePasswordActivity.java
index c27ad7e11..594866115 100644
--- a/briar-android/src/test/java/org/briarproject/briar/android/login/TestChangePasswordActivity.java
+++ b/briar-android/src/test/java/org/briarproject/briar/android/login/TestChangePasswordActivity.java
@@ -6,7 +6,8 @@ package org.briarproject.briar.android.login;
*/
public class TestChangePasswordActivity extends ChangePasswordActivity {
- public void setPasswordController(PasswordController passwordController) {
+ public void setPasswordController(
+ ChangePasswordController passwordController) {
this.passwordController = passwordController;
}