Setup Wizard that asks for Doze Mode exception

Keep checking if we are whitelisted and request it if not
This commit is contained in:
Torsten Grote
2017-09-26 10:04:48 -03:00
parent 1c4f20f76f
commit 8a81171739
45 changed files with 897 additions and 382 deletions

View File

@@ -27,8 +27,11 @@ import org.briarproject.briar.android.introduction.IntroductionMessageFragment;
import org.briarproject.briar.android.keyagreement.IntroFragment;
import org.briarproject.briar.android.keyagreement.KeyAgreementActivity;
import org.briarproject.briar.android.keyagreement.ShowQrCodeFragment;
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.PasswordActivity;
import org.briarproject.briar.android.login.PasswordFragment;
import org.briarproject.briar.android.login.SetupActivity;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.panic.PanicPreferencesActivity;
@@ -148,6 +151,10 @@ public interface ActivityComponent {
void inject(RssFeedManageActivity activity);
// Fragments
void inject(AuthorNameFragment fragment);
void inject(PasswordFragment fragment);
void inject(DozeFragment fragment);
void inject(ContactListFragment fragment);
void inject(CreateGroupFragment fragment);

View File

@@ -12,11 +12,13 @@ import android.view.ViewGroup.LayoutParams;
import android.view.inputmethod.InputMethodManager;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.briar.R;
import org.briarproject.briar.android.AndroidComponent;
import org.briarproject.briar.android.BriarApplication;
import org.briarproject.briar.android.DestroyableContext;
import org.briarproject.briar.android.controller.ActivityLifecycleController;
import org.briarproject.briar.android.forum.ForumModule;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.ScreenFilterDialogFragment;
import org.briarproject.briar.android.widget.TapSafeFrameLayout;
import org.briarproject.briar.android.widget.TapSafeFrameLayout.OnTapFilteredListener;
@@ -113,6 +115,22 @@ public abstract class BaseActivity extends AppCompatActivity
}
}
protected void showInitialFragment(BaseFragment f) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
.commit();
}
public void showNextFragment(BaseFragment f) {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.step_next_in,
R.anim.step_previous_out, R.anim.step_previous_in,
R.anim.step_next_out)
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
.addToBackStack(f.getUniqueTag())
.commit();
}
private void showScreenFilterWarning() {
if (dialogFrag != null && dialogFrag.isVisible()) return;
Set<String> apps = screenFilterMonitor.getApps();

View File

@@ -14,7 +14,6 @@ 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.ResultHandler;
import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.login.PasswordActivity;
import org.briarproject.briar.android.panic.ExitActivity;
@@ -64,22 +63,6 @@ public abstract class BriarActivity extends BaseActivity {
}
}
protected void showInitialFragment(BaseFragment f) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
.commit();
}
public void showNextFragment(BaseFragment f) {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.step_next_in,
R.anim.step_previous_out, R.anim.step_previous_in,
R.anim.step_next_out)
.replace(R.id.fragmentContainer, f, f.getUniqueTag())
.addToBackStack(f.getUniqueTag())
.commit();
}
public void setSceneTransitionAnimation() {
if (Build.VERSION.SDK_INT < 21) return;
Transition slide = new Slide(Gravity.RIGHT);

View File

@@ -3,13 +3,13 @@ package org.briarproject.briar.android.activity;
public interface RequestCodes {
int REQUEST_PASSWORD = 1;
int REQUEST_BLUETOOTH = 2;
int REQUEST_INTRODUCTION = 3;
int REQUEST_GROUP_INVITE = 4;
int REQUEST_SHARE_FORUM = 5;
int REQUEST_WRITE_BLOG_POST = 6;
int REQUEST_SHARE_BLOG = 7;
int REQUEST_RINGTONE = 8;
int REQUEST_PERMISSION_CAMERA = 9;
int REQUEST_INTRODUCTION = 2;
int REQUEST_GROUP_INVITE = 3;
int REQUEST_SHARE_FORUM = 4;
int REQUEST_WRITE_BLOG_POST = 5;
int REQUEST_SHARE_BLOG = 6;
int REQUEST_RINGTONE = 7;
int REQUEST_PERMISSION_CAMERA = 8;
int REQUEST_DOZE_WHITELISTING = 9;
}

View File

@@ -0,0 +1,84 @@
package org.briarproject.briar.android.login;
import android.os.Bundle;
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.widget.Button;
import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import static android.view.inputmethod.EditorInfo.IME_ACTION_NEXT;
import static android.view.inputmethod.EditorInfo.IME_ACTION_NONE;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.briar.android.util.UiUtils.setError;
public class AuthorNameFragment extends SetupFragment {
private final static String TAG = AuthorNameFragment.class.getName();
private TextInputLayout authorNameWrapper;
private TextInputEditText authorNameInput;
private Button nextButton;
public static AuthorNameFragment newInstance() {
return new AuthorNameFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().setTitle(getString(R.string.setup_title));
View v =
inflater.inflate(R.layout.fragment_setup_author_name, container,
false);
authorNameWrapper =
(TextInputLayout) v.findViewById(R.id.nickname_entry_wrapper);
authorNameInput =
(TextInputEditText) v.findViewById(R.id.nickname_entry);
nextButton = (Button) v.findViewById(R.id.next);
authorNameInput.addTextChangedListener(this);
nextButton.setOnClickListener(this);
return v;
}
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
}
@Override
protected String getHelpText() {
return getString(R.string.setup_name_explanation);
}
@Override
public void onTextChanged(CharSequence authorName, int i, int i1, int i2) {
int authorNameLength = StringUtils.toUtf8(authorName.toString()).length;
boolean error = authorNameLength > MAX_AUTHOR_NAME_LENGTH;
setError(authorNameWrapper, getString(R.string.name_too_long), error);
boolean enabled = authorNameLength > 0 && !error;
authorNameInput
.setImeOptions(enabled ? IME_ACTION_NEXT : IME_ACTION_NONE);
authorNameInput.setOnEditorActionListener(enabled ? this : null);
nextButton.setEnabled(enabled);
}
@Override
public void onClick(View view) {
setupController.setAuthorName(authorNameInput.getText().toString());
}
}

View File

@@ -32,8 +32,6 @@ public class ChangePasswordActivity extends BaseActivity
@Inject
protected PasswordController passwordController;
@Inject
protected SetupController setupController;
private TextInputLayout currentPasswordEntryWrapper;
private TextInputLayout newPasswordEntryWrapper;
@@ -105,7 +103,7 @@ public class ChangePasswordActivity extends BaseActivity
String secondPassword = newPasswordConfirmation.getText().toString();
boolean passwordsMatch = firstPassword.equals(secondPassword);
float strength =
setupController.estimatePasswordStrength(firstPassword);
passwordController.estimatePasswordStrength(firstPassword);
strengthMeter.setStrength(strength);
UiUtils.setError(newPasswordEntryWrapper,
getString(R.string.password_too_weak),

View File

@@ -0,0 +1,95 @@
package org.briarproject.briar.android.login;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.util.UiUtils;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
@TargetApi(23)
public class DozeFragment extends SetupFragment {
private final static String TAG = DozeFragment.class.getName();
private Button dozeButton;
private ProgressBar progressBar;
public static DozeFragment newInstance() {
return new DozeFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().setTitle(getString(R.string.setup_doze_title));
View v =
inflater.inflate(R.layout.fragment_setup_doze, container,
false);
dozeButton = (Button) v.findViewById(R.id.dozeButton);
progressBar = (ProgressBar) v.findViewById(R.id.progress);
dozeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
askForDozeWhitelisting();
}
});
return v;
}
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
}
@Override
protected String getHelpText() {
return getString(R.string.setup_doze_explanation);
}
@Override
public void onActivityResult(int request, int result, Intent data) {
super.onActivityResult(request, result, data);
if (request == REQUEST_DOZE_WHITELISTING) {
if (!setupController.needsDozeWhitelisting()) {
dozeButton.setEnabled(false);
onClick(dozeButton);
} else {
showOnboardingDialog(getContext(), getHelpText());
}
}
}
@SuppressLint("BatteryLife")
private void askForDozeWhitelisting() {
Intent i = UiUtils.getDozeWhitelistingIntent(getContext());
startActivityForResult(i, REQUEST_DOZE_WHITELISTING);
}
@Override
public void onClick(View view) {
dozeButton.setVisibility(INVISIBLE);
progressBar.setVisibility(VISIBLE);
setupController.createAccount();
}
}

View File

@@ -7,9 +7,12 @@ import org.briarproject.briar.android.controller.handler.ResultHandler;
@NotNullByDefault
public interface PasswordController extends ConfigController {
float estimatePasswordStrength(String password);
void validatePassword(String password,
ResultHandler<Boolean> resultHandler);
void changePassword(String password, String newPassword,
ResultHandler<Boolean> resultHandler);
}

View File

@@ -4,6 +4,7 @@ import android.content.SharedPreferences;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -27,14 +28,22 @@ public class PasswordControllerImpl extends ConfigControllerImpl
protected final Executor cryptoExecutor;
protected final CryptoComponent crypto;
private final PasswordStrengthEstimator strengthEstimator;
@Inject
PasswordControllerImpl(SharedPreferences briarPrefs,
DatabaseConfig databaseConfig,
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto) {
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
PasswordStrengthEstimator strengthEstimator) {
super(briarPrefs, databaseConfig);
this.cryptoExecutor = cryptoExecutor;
this.crypto = crypto;
this.strengthEstimator = strengthEstimator;
}
@Override
public float estimatePasswordStrength(String password) {
return strengthEstimator.estimateStrength(password);
}
@Override

View File

@@ -0,0 +1,117 @@
package org.briarproject.briar.android.login;
import android.os.Bundle;
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.widget.Button;
import android.widget.ProgressBar;
import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.util.UiUtils;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
public class PasswordFragment extends SetupFragment {
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;
public static PasswordFragment newInstance() {
return new PasswordFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getActivity().setTitle(getString(R.string.setup_password_intro));
View v =
inflater.inflate(R.layout.fragment_setup_password, container,
false);
strengthMeter = (StrengthMeter) v.findViewById(R.id.strength_meter);
passwordEntryWrapper =
(TextInputLayout) v.findViewById(R.id.password_entry_wrapper);
passwordEntry = (TextInputEditText) v.findViewById(R.id.password_entry);
passwordConfirmationWrapper =
(TextInputLayout) v.findViewById(R.id.password_confirm_wrapper);
passwordConfirmation =
(TextInputEditText) v.findViewById(R.id.password_confirm);
nextButton = (Button) v.findViewById(R.id.next);
progressBar = (ProgressBar) v.findViewById(R.id.progress);
passwordEntry.addTextChangedListener(this);
passwordConfirmation.addTextChangedListener(this);
nextButton.setOnClickListener(this);
return v;
}
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void injectFragment(ActivityComponent component) {
component.inject(this);
// the controller is not yet available in onCreateView()
if (!setupController.needsDozeWhitelisting()) {
nextButton.setText(R.string.create_account_button);
}
}
@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) {
if (!setupController.needsDozeWhitelisting()) {
nextButton.setVisibility(INVISIBLE);
progressBar.setVisibility(VISIBLE);
}
String password = passwordEntry.getText().toString();
setupController.setPassword(password);
setupController.showDozeOrCreateAccount();
}
}

View File

@@ -1,157 +1,64 @@
package org.briarproject.briar.android.login;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.TextInputLayout;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import org.briarproject.bramble.util.StringUtils;
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.handler.UiResultHandler;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.util.UiUtils;
import javax.inject.Inject;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static org.briarproject.bramble.api.crypto.PasswordStrengthEstimator.QUITE_WEAK;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
public class SetupActivity extends BaseActivity implements OnClickListener,
OnEditorActionListener {
public class SetupActivity extends BaseActivity
implements BaseFragmentListener {
@Inject
SetupController setupController;
private TextInputLayout nicknameEntryWrapper;
private TextInputLayout passwordEntryWrapper;
private TextInputLayout passwordConfirmationWrapper;
private EditText nicknameEntry;
private EditText passwordEntry;
private EditText passwordConfirmation;
private StrengthMeter strengthMeter;
private Button createAccountButton;
private ProgressBar progress;
@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);
setContentView(R.layout.activity_setup);
setContentView(R.layout.activity_fragment_container);
nicknameEntryWrapper =
(TextInputLayout) findViewById(R.id.nickname_entry_wrapper);
passwordEntryWrapper =
(TextInputLayout) findViewById(R.id.password_entry_wrapper);
passwordConfirmationWrapper =
(TextInputLayout) findViewById(R.id.password_confirm_wrapper);
nicknameEntry = (EditText) findViewById(R.id.nickname_entry);
passwordEntry = (EditText) findViewById(R.id.password_entry);
passwordConfirmation = (EditText) findViewById(R.id.password_confirm);
strengthMeter = (StrengthMeter) findViewById(R.id.strength_meter);
createAccountButton = (Button) findViewById(R.id.create_account);
progress = (ProgressBar) findViewById(R.id.progress_wheel);
TextWatcher tw = 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) {
enableOrDisableContinueButton();
}
@Override
public void afterTextChanged(Editable s) {
}
};
nicknameEntry.addTextChangedListener(tw);
passwordEntry.addTextChangedListener(tw);
passwordConfirmation.addTextChangedListener(tw);
passwordConfirmation.setOnEditorActionListener(this);
createAccountButton.setOnClickListener(this);
if (state == null) {
showInitialFragment(AuthorNameFragment.newInstance());
}
}
@Override
public void injectActivity(ActivityComponent component) {
component.inject(this);
setupController.setSetupActivity(this);
}
private void enableOrDisableContinueButton() {
if (progress == null) return; // Not created yet
if (passwordEntry.getText().length() > 0 && passwordEntry.hasFocus())
strengthMeter.setVisibility(VISIBLE);
else strengthMeter.setVisibility(GONE);
String nickname = nicknameEntry.getText().toString();
int nicknameLength = StringUtils.toUtf8(nickname).length;
String firstPassword = passwordEntry.getText().toString();
String secondPassword = passwordConfirmation.getText().toString();
boolean passwordsMatch = firstPassword.equals(secondPassword);
float strength =
setupController.estimatePasswordStrength(firstPassword);
strengthMeter.setStrength(strength);
UiUtils.setError(nicknameEntryWrapper,
getString(R.string.name_too_long),
nicknameLength > MAX_AUTHOR_NAME_LENGTH);
UiUtils.setError(passwordEntryWrapper,
getString(R.string.password_too_weak),
firstPassword.length() > 0 && strength < QUITE_WEAK);
UiUtils.setError(passwordConfirmationWrapper,
getString(R.string.passwords_do_not_match),
secondPassword.length() > 0 && !passwordsMatch);
createAccountButton.setEnabled(nicknameLength > 0
&& nicknameLength <= MAX_AUTHOR_NAME_LENGTH
&& passwordsMatch && strength >= QUITE_WEAK);
public void showPasswordFragment() {
showNextFragment(PasswordFragment.newInstance());
}
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
hideSoftKeyboard(v);
return true;
@TargetApi(23)
public void showDozeFragment() {
showNextFragment(DozeFragment.newInstance());
}
@Override
public void onClick(View view) {
// Replace the button with a progress bar
createAccountButton.setVisibility(INVISIBLE);
progress.setVisibility(VISIBLE);
String nickname = nicknameEntry.getText().toString();
String password = passwordEntry.getText().toString();
setupController.storeAuthorInfo(nickname, password,
new UiResultHandler<Void>(this) {
@Override
public void onResultUi(Void result) {
showMain();
}
});
}
private void showMain() {
public void showApp() {
Intent i = new Intent(this, NavDrawerActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
supportFinishAfterTransition();
overridePendingTransition(R.anim.screen_new_in, R.anim.screen_old_out);
}
@Override
@Deprecated
public void runOnDbThread(Runnable runnable) {
throw new RuntimeException("Don't use this deprecated method here.");
}
}

View File

@@ -6,9 +6,25 @@ import org.briarproject.briar.android.controller.handler.ResultHandler;
@NotNullByDefault
public interface SetupController {
void setSetupActivity(SetupActivity setupActivity);
boolean needsDozeWhitelisting();
void setAuthorName(String authorName);
void setPassword(String password);
float estimatePasswordStrength(String password);
void storeAuthorInfo(String nickname, String password,
ResultHandler<Void> resultHandler);
/**
* This should be called after the author name and the password have been
* set. It decides whether to ask for doze exception or create the account
* right away.
*/
void showDozeOrCreateAccount();
void createAccount();
void createAccount(final ResultHandler<Void> resultHandler);
}

View File

@@ -1,6 +1,7 @@
package org.briarproject.briar.android.login;
import android.content.SharedPreferences;
import android.support.annotation.Nullable;
import org.briarproject.bramble.api.crypto.CryptoComponent;
import org.briarproject.bramble.api.crypto.CryptoExecutor;
@@ -9,6 +10,8 @@ import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.android.controller.handler.ResultHandler;
import org.briarproject.briar.android.controller.handler.UiResultHandler;
import org.briarproject.briar.android.util.UiUtils;
import java.util.concurrent.Executor;
@@ -18,29 +21,75 @@ import javax.inject.Inject;
public class SetupControllerImpl extends PasswordControllerImpl
implements SetupController {
private final PasswordStrengthEstimator strengthEstimator;
@Nullable
private String authorName, password;
@Nullable
private SetupActivity setupActivity;
@Inject
SetupControllerImpl(SharedPreferences briarPrefs,
DatabaseConfig databaseConfig,
@CryptoExecutor Executor cryptoExecutor, CryptoComponent crypto,
PasswordStrengthEstimator strengthEstimator) {
super(briarPrefs, databaseConfig, cryptoExecutor, crypto);
this.strengthEstimator = strengthEstimator;
super(briarPrefs, databaseConfig, cryptoExecutor, crypto,
strengthEstimator);
}
@Override
public float estimatePasswordStrength(String password) {
return strengthEstimator.estimateStrength(password);
public void setSetupActivity(SetupActivity setupActivity) {
this.setupActivity = setupActivity;
}
@Override
public void storeAuthorInfo(final String nickname, final String password,
final ResultHandler<Void> resultHandler) {
public boolean needsDozeWhitelisting() {
if (setupActivity == null) throw new IllegalStateException();
return UiUtils.needsDozeWhitelisting(setupActivity);
}
@Override
public void setAuthorName(String authorName) {
this.authorName = authorName;
if (setupActivity == null) throw new IllegalStateException();
setupActivity.showPasswordFragment();
}
@Override
public void setPassword(String password) {
this.password = password;
}
@Override
public void showDozeOrCreateAccount() {
if (setupActivity == null) throw new IllegalStateException();
if (needsDozeWhitelisting()) {
setupActivity.showDozeFragment();
} else {
createAccount();
}
}
@Override
public void createAccount() {
final UiResultHandler<Void> resultHandler =
new UiResultHandler<Void>(setupActivity) {
@Override
public void onResultUi(Void result) {
if (setupActivity == null)
throw new IllegalStateException();
setupActivity.showApp();
}
};
createAccount(resultHandler);
}
@Override
public void createAccount(final ResultHandler<Void> resultHandler) {
if (authorName == null || password == null)
throw new IllegalStateException();
cryptoExecutor.execute(new Runnable() {
@Override
public void run() {
databaseConfig.setLocalAuthorName(nickname);
databaseConfig.setLocalAuthorName(authorName);
SecretKey key = crypto.generateSecretKey();
databaseConfig.setEncryptionKey(key);
String hex = encryptDatabaseKey(key, password);

View File

@@ -0,0 +1,66 @@
package org.briarproject.briar.android.login;
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.OnClickListener;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import org.briarproject.briar.R;
import org.briarproject.briar.android.fragment.BaseFragment;
import javax.inject.Inject;
import static org.briarproject.briar.android.util.UiUtils.showOnboardingDialog;
abstract class SetupFragment extends BaseFragment implements TextWatcher,
OnEditorActionListener, OnClickListener {
@Inject
SetupController setupController;
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.help_action, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_help) {
showOnboardingDialog(getContext(), getHelpText());
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
protected abstract String getHelpText();
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1,
int i2) {
// noop
}
@Override
public void onTextChanged(CharSequence authorName, int i, int i1, int i2) {
// noop
}
@Override
public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
onClick(textView);
return true;
}
@Override
public void afterTextChanged(Editable editable) {
// noop
}
}

View File

@@ -1,14 +1,19 @@
package org.briarproject.briar.android.navdrawer;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.design.widget.NavigationView.OnNavigationItemSelectedListener;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -49,9 +54,12 @@ import static android.support.v4.view.GravityCompat.START;
import static android.support.v4.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.briarproject.briar.android.activity.RequestCodes.REQUEST_DOZE_WHITELISTING;
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.NO;
import static org.briarproject.briar.android.navdrawer.NavDrawerController.ExpiryWarning.UPDATE;
import static org.briarproject.briar.android.util.UiUtils.getDaysUntilExpiry;
import static org.briarproject.briar.android.util.UiUtils.getDozeWhitelistingIntent;
import static org.briarproject.briar.android.util.UiUtils.needsDozeWhitelisting;
public class NavDrawerActivity extends BriarActivity implements
BaseFragmentListener, TransportStateListener,
@@ -134,6 +142,7 @@ public class NavDrawerActivity extends BriarActivity implements
}
@Override
@SuppressLint("NewApi")
public void onStart() {
super.onStart();
updateTransports();
@@ -143,6 +152,7 @@ public class NavDrawerActivity extends BriarActivity implements
if (expiry != NO) showExpiryWarning(expiry);
}
});
if (needsDozeWhitelisting(this)) requestDozeWhitelisting();
}
private void exitIfStartupFailed(Intent intent) {
@@ -178,7 +188,7 @@ public class NavDrawerActivity extends BriarActivity implements
}
@Override
public boolean onNavigationItemSelected(MenuItem item) {
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
drawerLayout.closeDrawer(START);
clearBackStack();
loadFragment(item.getItemId());
@@ -311,6 +321,24 @@ public class NavDrawerActivity extends BriarActivity implements
expiryWarning.setVisibility(VISIBLE);
}
@TargetApi(23)
private void requestDozeWhitelisting() {
new AlertDialog.Builder(this, R.style.BriarDialogTheme)
.setMessage(R.string.setup_doze_intro)
.setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
Intent i = getDozeWhitelistingIntent(
NavDrawerActivity.this);
startActivityForResult(i,
REQUEST_DOZE_WHITELISTING);
}
})
.show();
}
private void initializeTransports(final LayoutInflater inflater) {
transports = new ArrayList<>(3);

View File

@@ -1,14 +1,18 @@
package org.briarproject.briar.android.util;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.text.Spannable;
@@ -23,14 +27,16 @@ import android.view.View;
import android.widget.TextView;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.briar.BuildConfig;
import org.briarproject.briar.R;
import org.briarproject.briar.android.view.ArticleMovementMethod;
import org.briarproject.briar.android.widget.LinkDialogFragment;
import javax.annotation.Nullable;
import static android.content.Intent.*;
import static android.content.Context.POWER_SERVICE;
import static android.content.Intent.CATEGORY_DEFAULT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE;
@@ -38,7 +44,7 @@ import static android.text.format.DateUtils.FORMAT_ABBREV_TIME;
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static org.briarproject.briar.BuildConfig.*;
import static org.briarproject.briar.BuildConfig.APPLICATION_ID;
import static org.briarproject.briar.android.BriarApplication.EXPIRY_DATE;
public class UiUtils {
@@ -149,4 +155,37 @@ public class UiUtils {
}
};
}
public static void showOnboardingDialog(Context ctx, String text) {
new AlertDialog.Builder(ctx, R.style.OnboardingDialogTheme)
.setMessage(text)
.setNeutralButton(R.string.got_it,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
dialog.cancel();
}
})
.show();
}
public static boolean needsDozeWhitelisting(Context ctx) {
if (Build.VERSION.SDK_INT < 23) return false;
PowerManager pm =
(PowerManager) ctx.getSystemService(POWER_SERVICE);
String packageName = ctx.getPackageName();
if (pm == null) throw new AssertionError();
return !pm.isIgnoringBatteryOptimizations(packageName);
}
@TargetApi(23)
@SuppressLint("BatteryLife")
public static Intent getDozeWhitelistingIntent(Context ctx) {
Intent i = new Intent();
i.setAction(ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
i.setData(Uri.parse("package:" + ctx.getPackageName()));
return i;
}
}