Apply KBS Lock fixes and pluralization

This commit is contained in:
Alex Hart 2020-02-01 13:13:53 -04:00 committed by Greyson Parrelli
parent 4a8c312e0a
commit 279dcb1428
14 changed files with 213 additions and 158 deletions

View File

@ -4,7 +4,7 @@ import androidx.annotation.CheckResult;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.lock.v2.KbsKeyboardType; import org.thoughtcrime.securesms.lock.v2.PinKeyboardType;
import org.thoughtcrime.securesms.util.JsonUtils; import org.thoughtcrime.securesms.util.JsonUtils;
import org.whispersystems.signalservice.api.RegistrationLockData; import org.whispersystems.signalservice.api.RegistrationLockData;
import org.whispersystems.signalservice.api.kbs.MasterKey; import org.whispersystems.signalservice.api.kbs.MasterKey;
@ -117,14 +117,14 @@ public final class KbsValues {
} }
} }
public void setKeyboardType(@NonNull KbsKeyboardType keyboardType) { public void setKeyboardType(@NonNull PinKeyboardType keyboardType) {
store.beginWrite() store.beginWrite()
.putString(KEYBOARD_TYPE, keyboardType.getCode()) .putString(KEYBOARD_TYPE, keyboardType.getCode())
.commit(); .commit();
} }
@CheckResult @CheckResult
public @NonNull KbsKeyboardType getKeyboardType() { public @NonNull PinKeyboardType getKeyboardType() {
return KbsKeyboardType.fromCode(store.getString(KEYBOARD_TYPE, null)); return PinKeyboardType.fromCode(store.getString(KEYBOARD_TYPE, null));
} }
} }

View File

@ -132,15 +132,15 @@ abstract class BaseKbsPinFragment<ViewModel extends BaseKbsPinViewModel> extends
return true; return true;
} }
private void updateKeyboard(@NonNull KbsKeyboardType keyboard) { private void updateKeyboard(@NonNull PinKeyboardType keyboard) {
boolean isAlphaNumeric = keyboard == KbsKeyboardType.ALPHA_NUMERIC; boolean isAlphaNumeric = keyboard == PinKeyboardType.ALPHA_NUMERIC;
input.setInputType(isAlphaNumeric ? InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD input.setInputType(isAlphaNumeric ? InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
: InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD); : InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
} }
private @StringRes int resolveKeyboardToggleText(@NonNull KbsKeyboardType keyboard) { private @StringRes int resolveKeyboardToggleText(@NonNull PinKeyboardType keyboard) {
if (keyboard == KbsKeyboardType.ALPHA_NUMERIC) { if (keyboard == PinKeyboardType.ALPHA_NUMERIC) {
return R.string.BaseKbsPinFragment__create_numeric_pin; return R.string.BaseKbsPinFragment__create_numeric_pin;
} else { } else {
return R.string.BaseKbsPinFragment__create_alphanumeric_pin; return R.string.BaseKbsPinFragment__create_alphanumeric_pin;

View File

@ -1,15 +1,12 @@
package org.thoughtcrime.securesms.lock.v2; package org.thoughtcrime.securesms.lock.v2;
import androidx.annotation.MainThread; import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
interface BaseKbsPinViewModel { interface BaseKbsPinViewModel {
LiveData<KbsPin> getUserEntry(); LiveData<KbsPin> getUserEntry();
LiveData<KbsKeyboardType> getKeyboard(); LiveData<PinKeyboardType> getKeyboard();
@MainThread @MainThread
void setUserEntry(String userEntry); void setUserEntry(String userEntry);

View File

@ -41,7 +41,7 @@ public class ConfirmKbsPinFragment extends BaseKbsPinFragment<ConfirmKbsPinViewM
@Override @Override
protected ConfirmKbsPinViewModel initializeViewModel() { protected ConfirmKbsPinViewModel initializeViewModel() {
KbsPin userEntry = Preconditions.checkNotNull(args.getUserEntry()); KbsPin userEntry = Preconditions.checkNotNull(args.getUserEntry());
KbsKeyboardType keyboard = args.getKeyboard(); PinKeyboardType keyboard = args.getKeyboard();
ConfirmKbsPinRepository repository = new ConfirmKbsPinRepository(); ConfirmKbsPinRepository repository = new ConfirmKbsPinRepository();
ConfirmKbsPinViewModel.Factory factory = new ConfirmKbsPinViewModel.Factory(userEntry, keyboard, repository); ConfirmKbsPinViewModel.Factory factory = new ConfirmKbsPinViewModel.Factory(userEntry, keyboard, repository);

View File

@ -12,13 +12,11 @@ import org.thoughtcrime.securesms.lock.PinHashing;
import org.thoughtcrime.securesms.lock.RegistrationLockReminders; import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.megaphone.Megaphones; import org.thoughtcrime.securesms.megaphone.Megaphones;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask; import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.whispersystems.signalservice.api.KeyBackupService; import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.KeyBackupServicePinException; import org.whispersystems.signalservice.api.KeyBackupServicePinException;
import org.whispersystems.signalservice.api.RegistrationLockData; import org.whispersystems.signalservice.api.RegistrationLockData;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.kbs.HashedPin; import org.whispersystems.signalservice.api.kbs.HashedPin;
import org.whispersystems.signalservice.api.kbs.MasterKey; import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException; import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
@ -29,7 +27,7 @@ final class ConfirmKbsPinRepository {
private static final String TAG = Log.tag(ConfirmKbsPinRepository.class); private static final String TAG = Log.tag(ConfirmKbsPinRepository.class);
void setPin(@NonNull KbsPin kbsPin, @NonNull KbsKeyboardType keyboard, @NonNull Consumer<PinSetResult> resultConsumer) { void setPin(@NonNull KbsPin kbsPin, @NonNull PinKeyboardType keyboard, @NonNull Consumer<PinSetResult> resultConsumer) {
Context context = ApplicationDependencies.getApplication(); Context context = ApplicationDependencies.getApplication();
String pinValue = kbsPin.toString(); String pinValue = kbsPin.toString();

View File

@ -16,14 +16,14 @@ final class ConfirmKbsPinViewModel extends ViewModel implements BaseKbsPinViewMo
private final ConfirmKbsPinRepository repository; private final ConfirmKbsPinRepository repository;
private final MutableLiveData<KbsPin> userEntry = new MutableLiveData<>(KbsPin.EMPTY); private final MutableLiveData<KbsPin> userEntry = new MutableLiveData<>(KbsPin.EMPTY);
private final MutableLiveData<KbsKeyboardType> keyboard = new MutableLiveData<>(KbsKeyboardType.NUMERIC); private final MutableLiveData<PinKeyboardType> keyboard = new MutableLiveData<>(PinKeyboardType.NUMERIC);
private final MutableLiveData<SaveAnimation> saveAnimation = new MutableLiveData<>(SaveAnimation.NONE); private final MutableLiveData<SaveAnimation> saveAnimation = new MutableLiveData<>(SaveAnimation.NONE);
private final MutableLiveData<Label> label = new MutableLiveData<>(Label.RE_ENTER_PIN); private final MutableLiveData<Label> label = new MutableLiveData<>(Label.RE_ENTER_PIN);
private final KbsPin pinToConfirm; private final KbsPin pinToConfirm;
private ConfirmKbsPinViewModel(@NonNull KbsPin pinToConfirm, private ConfirmKbsPinViewModel(@NonNull KbsPin pinToConfirm,
@NonNull KbsKeyboardType keyboard, @NonNull PinKeyboardType keyboard,
@NonNull ConfirmKbsPinRepository repository) @NonNull ConfirmKbsPinRepository repository)
{ {
this.keyboard.setValue(keyboard); this.keyboard.setValue(keyboard);
@ -65,7 +65,7 @@ final class ConfirmKbsPinViewModel extends ViewModel implements BaseKbsPinViewMo
} }
@Override @Override
public LiveData<KbsKeyboardType> getKeyboard() { public LiveData<PinKeyboardType> getKeyboard() {
return keyboard; return keyboard;
} }
@ -109,11 +109,11 @@ final class ConfirmKbsPinViewModel extends ViewModel implements BaseKbsPinViewMo
static final class Factory implements ViewModelProvider.Factory { static final class Factory implements ViewModelProvider.Factory {
private final KbsPin pinToConfirm; private final KbsPin pinToConfirm;
private final KbsKeyboardType keyboard; private final PinKeyboardType keyboard;
private final ConfirmKbsPinRepository repository; private final ConfirmKbsPinRepository repository;
Factory(@NonNull KbsPin pinToConfirm, Factory(@NonNull KbsPin pinToConfirm,
@NonNull KbsKeyboardType keyboard, @NonNull PinKeyboardType keyboard,
@NonNull ConfirmKbsPinRepository repository) @NonNull ConfirmKbsPinRepository repository)
{ {
this.pinToConfirm = pinToConfirm; this.pinToConfirm = pinToConfirm;

View File

@ -46,7 +46,7 @@ public class CreateKbsPinFragment extends BaseKbsPinFragment<CreateKbsPinViewMod
return viewModel; return viewModel;
} }
private void onConfirmPin(@NonNull KbsPin userEntry, @NonNull KbsKeyboardType keyboard) { private void onConfirmPin(@NonNull KbsPin userEntry, @NonNull PinKeyboardType keyboard) {
CreateKbsPinFragmentDirections.ActionConfirmPin action = CreateKbsPinFragmentDirections.actionConfirmPin(); CreateKbsPinFragmentDirections.ActionConfirmPin action = CreateKbsPinFragmentDirections.actionConfirmPin();
action.setUserEntry(userEntry); action.setUserEntry(userEntry);
@ -56,8 +56,8 @@ public class CreateKbsPinFragment extends BaseKbsPinFragment<CreateKbsPinViewMod
Navigation.findNavController(requireView()).navigate(action); Navigation.findNavController(requireView()).navigate(action);
} }
private String getLabelText(@NonNull KbsKeyboardType keyboard) { private String getLabelText(@NonNull PinKeyboardType keyboard) {
if (keyboard == KbsKeyboardType.ALPHA_NUMERIC) { if (keyboard == PinKeyboardType.ALPHA_NUMERIC) {
return getPinLengthRestrictionText(R.plurals.CreateKbsPinFragment__pin_must_be_at_least_characters); return getPinLengthRestrictionText(R.plurals.CreateKbsPinFragment__pin_must_be_at_least_characters);
} else { } else {
return getPinLengthRestrictionText(R.plurals.CreateKbsPinFragment__pin_must_be_at_least_digits); return getPinLengthRestrictionText(R.plurals.CreateKbsPinFragment__pin_must_be_at_least_digits);

View File

@ -5,17 +5,14 @@ import androidx.annotation.NonNull;
import androidx.core.util.Preconditions; import androidx.core.util.Preconditions;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import org.thoughtcrime.securesms.util.SingleLiveEvent; import org.thoughtcrime.securesms.util.SingleLiveEvent;
import org.thoughtcrime.securesms.util.livedata.LiveDataPair;
public final class CreateKbsPinViewModel extends ViewModel implements BaseKbsPinViewModel { public final class CreateKbsPinViewModel extends ViewModel implements BaseKbsPinViewModel {
private final MutableLiveData<KbsPin> userEntry = new MutableLiveData<>(KbsPin.EMPTY); private final MutableLiveData<KbsPin> userEntry = new MutableLiveData<>(KbsPin.EMPTY);
private final MutableLiveData<KbsKeyboardType> keyboard = new MutableLiveData<>(KbsKeyboardType.NUMERIC); private final MutableLiveData<PinKeyboardType> keyboard = new MutableLiveData<>(PinKeyboardType.NUMERIC);
private final SingleLiveEvent<NavigationEvent> events = new SingleLiveEvent<>(); private final SingleLiveEvent<NavigationEvent> events = new SingleLiveEvent<>();
@Override @Override
@ -24,7 +21,7 @@ public final class CreateKbsPinViewModel extends ViewModel implements BaseKbsPin
} }
@Override @Override
public LiveData<KbsKeyboardType> getKeyboard() { public LiveData<PinKeyboardType> getKeyboard() {
return keyboard; return keyboard;
} }
@ -51,9 +48,9 @@ public final class CreateKbsPinViewModel extends ViewModel implements BaseKbsPin
static final class NavigationEvent { static final class NavigationEvent {
private final KbsPin userEntry; private final KbsPin userEntry;
private final KbsKeyboardType keyboard; private final PinKeyboardType keyboard;
NavigationEvent(@NonNull KbsPin userEntry, @NonNull KbsKeyboardType keyboard) { NavigationEvent(@NonNull KbsPin userEntry, @NonNull PinKeyboardType keyboard) {
this.userEntry = userEntry; this.userEntry = userEntry;
this.keyboard = keyboard; this.keyboard = keyboard;
} }
@ -62,7 +59,7 @@ public final class CreateKbsPinViewModel extends ViewModel implements BaseKbsPin
return userEntry; return userEntry;
} }
KbsKeyboardType getKeyboard() { PinKeyboardType getKeyboard() {
return keyboard; return keyboard;
} }
} }

View File

@ -2,17 +2,17 @@ package org.thoughtcrime.securesms.lock.v2;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
public enum KbsKeyboardType { public enum PinKeyboardType {
NUMERIC("numeric"), NUMERIC("numeric"),
ALPHA_NUMERIC("alphaNumeric"); ALPHA_NUMERIC("alphaNumeric");
private final String code; private final String code;
KbsKeyboardType(String code) { PinKeyboardType(String code) {
this.code = code; this.code = code;
} }
KbsKeyboardType getOther() { public PinKeyboardType getOther() {
if (this == NUMERIC) return ALPHA_NUMERIC; if (this == NUMERIC) return ALPHA_NUMERIC;
else return NUMERIC; else return NUMERIC;
} }
@ -21,8 +21,8 @@ public enum KbsKeyboardType {
return code; return code;
} }
public static KbsKeyboardType fromCode(@Nullable String code) { public static PinKeyboardType fromCode(@Nullable String code) {
for (KbsKeyboardType type : KbsKeyboardType.values()) { for (PinKeyboardType type : PinKeyboardType.values()) {
if (type.code.equals(code)) { if (type.code.equals(code)) {
return type; return type;
} }

View File

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.registration.fragments; package org.thoughtcrime.securesms.registration.fragments;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.text.InputType; import android.text.InputType;
import android.text.TextUtils; import android.text.TextUtils;
@ -21,7 +22,7 @@ import com.dd.CircularProgressButton;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.v2.KbsKeyboardType; import org.thoughtcrime.securesms.lock.v2.PinKeyboardType;
import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.registration.service.CodeVerificationRequest; import org.thoughtcrime.securesms.registration.service.CodeVerificationRequest;
import org.thoughtcrime.securesms.registration.service.RegistrationService; import org.thoughtcrime.securesms.registration.service.RegistrationService;
@ -35,6 +36,7 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
private static final String TAG = Log.tag(RegistrationLockFragment.class); private static final String TAG = Log.tag(RegistrationLockFragment.class);
private EditText pinEntry; private EditText pinEntry;
private View forgotPin;
private CircularProgressButton pinButton; private CircularProgressButton pinButton;
private TextView errorLabel; private TextView errorLabel;
private TextView keyboardToggle; private TextView keyboardToggle;
@ -55,12 +57,12 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
pinButton = view.findViewById(R.id.kbs_lock_pin_confirm); pinButton = view.findViewById(R.id.kbs_lock_pin_confirm);
errorLabel = view.findViewById(R.id.kbs_lock_pin_input_label); errorLabel = view.findViewById(R.id.kbs_lock_pin_input_label);
keyboardToggle = view.findViewById(R.id.kbs_lock_keyboard_toggle); keyboardToggle = view.findViewById(R.id.kbs_lock_keyboard_toggle);
forgotPin = view.findViewById(R.id.kbs_lock_forgot_pin);
View pinForgotButton = view.findViewById(R.id.kbs_lock_forgot_pin);
timeRemaining = RegistrationLockFragmentArgs.fromBundle(requireArguments()).getTimeRemaining(); timeRemaining = RegistrationLockFragmentArgs.fromBundle(requireArguments()).getTimeRemaining();
pinForgotButton.setOnClickListener(v -> handleForgottenPin(timeRemaining)); forgotPin.setVisibility(View.GONE);
forgotPin.setOnClickListener(v -> handleForgottenPin(timeRemaining));
pinEntry.setImeOptions(EditorInfo.IME_ACTION_DONE); pinEntry.setImeOptions(EditorInfo.IME_ACTION_DONE);
pinEntry.setOnEditorActionListener((v, actionId, event) -> { pinEntry.setOnEditorActionListener((v, actionId, event) -> {
@ -78,20 +80,50 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
}); });
keyboardToggle.setOnClickListener((v) -> { keyboardToggle.setOnClickListener((v) -> {
KbsKeyboardType keyboardType = getPinEntryKeyboardType(); PinKeyboardType keyboardType = getPinEntryKeyboardType();
updateKeyboard(keyboardType); updateKeyboard(keyboardType.getOther());
keyboardToggle.setText(resolveKeyboardToggleText(keyboardType)); keyboardToggle.setText(resolveKeyboardToggleText(keyboardType));
}); });
PinKeyboardType keyboardType = getPinEntryKeyboardType().getOther();
keyboardToggle.setText(resolveKeyboardToggleText(keyboardType));
getModel().getTimeRemaining() getModel().getTimeRemaining()
.observe(getViewLifecycleOwner(), t -> timeRemaining = t); .observe(getViewLifecycleOwner(), t -> timeRemaining = t);
TokenResponse keyBackupCurrentToken = getModel().getKeyBackupCurrentToken();
if (keyBackupCurrentToken != null) {
int triesRemaining = keyBackupCurrentToken.getTries();
if (triesRemaining <= 3) {
int daysRemaining = getLockoutDays(timeRemaining);
new AlertDialog.Builder(requireContext())
.setTitle(R.string.RegistrationLockFragment__not_many_tries_left)
.setMessage(getTriesRemainingDialogMessage(triesRemaining, daysRemaining))
.setPositiveButton(android.R.string.ok, null)
.show();
} }
private KbsKeyboardType getPinEntryKeyboardType() { if (triesRemaining < 5) {
boolean isNumeric = (pinEntry.getImeOptions() & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_NUMBER; errorLabel.setText(requireContext().getResources().getQuantityString(R.plurals.RegistrationLockFragment__d_attempts_remaining, triesRemaining, triesRemaining));
}
}
}
return isNumeric ? KbsKeyboardType.NUMERIC : KbsKeyboardType.ALPHA_NUMERIC; private String getTriesRemainingDialogMessage(int triesRemaining, int daysRemaining) {
Resources resources = requireContext().getResources();
String tries = resources.getQuantityString(R.plurals.RegistrationLockFragment__you_have_d_attempts_remaining, triesRemaining, triesRemaining);
String days = resources.getQuantityString(R.plurals.RegistrationLockFragment__if_you_run_out_of_attempts_your_account_will_be_locked_for_d_days, daysRemaining, daysRemaining);
return tries + " " + days;
}
private PinKeyboardType getPinEntryKeyboardType() {
boolean isNumeric = (pinEntry.getInputType() & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_NUMBER;
return isNumeric ? PinKeyboardType.NUMERIC : PinKeyboardType.ALPHA_NUMERIC;
} }
private void handlePinEntry() { private void handlePinEntry() {
@ -133,7 +165,7 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
cancelSpinning(pinButton); cancelSpinning(pinButton);
pinEntry.getText().clear(); pinEntry.getText().clear();
errorLabel.setText(R.string.KbsLockFragment__incorrect_pin); errorLabel.setText(R.string.RegistrationLockFragment__incorrect_pin);
} }
@Override @Override
@ -157,19 +189,20 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
} }
if (triesRemaining == 3) { if (triesRemaining == 3) {
long daysRemaining = getLockoutDays(timeRemaining); int daysRemaining = getLockoutDays(timeRemaining);
new AlertDialog.Builder(requireContext()) new AlertDialog.Builder(requireContext())
.setTitle(R.string.KbsLockFragment__incorrect_pin) .setTitle(R.string.RegistrationLockFragment__incorrect_pin)
.setMessage(getString(R.string.KbsLockFragment__you_have_d_attempts_remaining, triesRemaining, daysRemaining, daysRemaining)) .setMessage(getTriesRemainingDialogMessage(triesRemaining, daysRemaining))
.setPositiveButton(android.R.string.ok, null) .setPositiveButton(android.R.string.ok, null)
.show(); .show();
} }
if (triesRemaining > 5) { if (triesRemaining > 5) {
errorLabel.setText(R.string.KbsLockFragment__incorrect_pin_try_again); errorLabel.setText(R.string.RegistrationLockFragment__incorrect_pin_try_again);
} else { } else {
errorLabel.setText(getString(R.string.KbsLockFragment__incorrect_pin_d_attempts_remaining, triesRemaining)); errorLabel.setText(requireContext().getResources().getQuantityString(R.plurals.RegistrationLockFragment__incorrect_pin_d_attempts_remaining, triesRemaining, triesRemaining));
forgotPin.setVisibility(View.VISIBLE);
} }
} }
@ -201,15 +234,16 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
} }
private void handleForgottenPin(long timeRemainingMs) { private void handleForgottenPin(long timeRemainingMs) {
int lockoutDays = getLockoutDays(timeRemainingMs);
new AlertDialog.Builder(requireContext()) new AlertDialog.Builder(requireContext())
.setTitle(R.string.KbsLockFragment__forgot_your_pin) .setTitle(R.string.RegistrationLockFragment__forgot_your_pin)
.setMessage(getString(R.string.KbsLockFragment__for_your_privacy_and_security_there_is_no_way_to_recover, getLockoutDays(timeRemainingMs))) .setMessage(requireContext().getResources().getQuantityString(R.plurals.RegistrationLockFragment__for_your_privacy_and_security_there_is_no_way_to_recover, lockoutDays, lockoutDays))
.setPositiveButton(android.R.string.ok, null) .setPositiveButton(android.R.string.ok, null)
.show(); .show();
} }
private static long getLockoutDays(long timeRemainingMs) { private static int getLockoutDays(long timeRemainingMs) {
return TimeUnit.MILLISECONDS.toDays(timeRemainingMs) + 1; return (int) TimeUnit.MILLISECONDS.toDays(timeRemainingMs) + 1;
} }
private void lockAccount(long timeRemaining) { private void lockAccount(long timeRemaining) {
@ -218,18 +252,18 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
Navigation.findNavController(requireView()).navigate(action); Navigation.findNavController(requireView()).navigate(action);
} }
private void updateKeyboard(@NonNull KbsKeyboardType keyboard) { private void updateKeyboard(@NonNull PinKeyboardType keyboard) {
boolean isAlphaNumeric = keyboard == KbsKeyboardType.ALPHA_NUMERIC; boolean isAlphaNumeric = keyboard == PinKeyboardType.ALPHA_NUMERIC;
pinEntry.setInputType(isAlphaNumeric ? InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD pinEntry.setInputType(isAlphaNumeric ? InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
: InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD); : InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
} }
private @StringRes static int resolveKeyboardToggleText(@NonNull KbsKeyboardType keyboard) { private @StringRes static int resolveKeyboardToggleText(@NonNull PinKeyboardType keyboard) {
if (keyboard == KbsKeyboardType.ALPHA_NUMERIC) { if (keyboard == PinKeyboardType.ALPHA_NUMERIC) {
return R.string.KbsLockFragment__enter_alphanumeric_pin; return R.string.RegistrationLockFragment__enter_alphanumeric_pin;
} else { } else {
return R.string.KbsLockFragment__enter_numeric_pin; return R.string.RegistrationLockFragment__enter_numeric_pin;
} }
} }
} }

View File

@ -17,7 +17,6 @@ import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver; import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
import org.thoughtcrime.securesms.lock.RegistrationLockReminders; import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
import org.thoughtcrime.securesms.lock.v2.KbsKeyboardType;
import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference; import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
import org.thoughtcrime.securesms.profiles.ProfileName; import org.thoughtcrime.securesms.profiles.ProfileName;

View File

@ -1,16 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView <TextView
android:id="@+id/kbs_lock_pin_title" android:id="@+id/kbs_lock_pin_title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:text="@string/KbsLockFragment__enter_your_pin" android:text="@string/RegistrationLockFragment__enter_your_pin"
android:textAppearance="@style/TextAppearance.Signal.Title1" android:textAppearance="@style/TextAppearance.Signal.Title1"
app:layout_constraintBottom_toTopOf="@id/kbs_lock_keyboard_toggle" app:layout_constraintBottom_toTopOf="@id/kbs_lock_keyboard_toggle"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
@ -25,7 +30,7 @@
android:layout_marginEnd="27dp" android:layout_marginEnd="27dp"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:minHeight="66dp" android:minHeight="66dp"
android:text="@string/KbsLockFragment__enter_the_pin_you_created" android:text="@string/RegistrationLockFragment__enter_the_pin_you_created"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/core_grey_60" android:textColor="@color/core_grey_60"
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_title" /> app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_title" />
@ -52,7 +57,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_input" app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_input"
tools:text="@string/KbsLockFragment__incorrect_pin_try_again" /> tools:text="@string/RegistrationLockFragment__incorrect_pin_try_again" />
<Button <Button
android:id="@+id/kbs_lock_forgot_pin" android:id="@+id/kbs_lock_forgot_pin"
@ -60,13 +65,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="32dp" android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="32dp" android:layout_marginEnd="32dp"
android:text="@string/KbsLockFragment__forgot_pin" android:text="@string/RegistrationLockFragment__forgot_pin"
android:textColor="@color/signal_primary" android:textColor="@color/signal_primary"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_input" /> app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_input_label" />
<Button <Button
android:id="@+id/kbs_lock_keyboard_toggle" android:id="@+id/kbs_lock_keyboard_toggle"
@ -77,6 +81,8 @@
android:layout_marginEnd="32dp" android:layout_marginEnd="32dp"
android:textColor="@color/signal_primary" android:textColor="@color/signal_primary"
app:layout_constraintBottom_toTopOf="@id/kbs_lock_pin_confirm" app:layout_constraintBottom_toTopOf="@id/kbs_lock_pin_confirm"
app:layout_constraintTop_toBottomOf="@id/kbs_lock_forgot_pin"
app:layout_constraintVertical_bias="1.0"
tools:text="Create Alphanumeric Pin" /> tools:text="Create Alphanumeric Pin" />
<com.dd.CircularProgressButton <com.dd.CircularProgressButton
@ -92,4 +98,5 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View File

@ -46,7 +46,7 @@
<argument <argument
android:name="keyboard" android:name="keyboard"
android:defaultValue="NUMERIC" android:defaultValue="NUMERIC"
app:argType="org.thoughtcrime.securesms.lock.v2.KbsKeyboardType" app:argType="org.thoughtcrime.securesms.lock.v2.PinKeyboardType"
app:nullable="false" /> app:nullable="false" />
</fragment> </fragment>

View File

@ -1735,18 +1735,41 @@
<string name="AccountLockedFragment__learn_more_url">https://signal.org/blog/secure-value-recovery/</string> <string name="AccountLockedFragment__learn_more_url">https://signal.org/blog/secure-value-recovery/</string>
<!-- KbsLockFragment --> <!-- KbsLockFragment -->
<string name="KbsLockFragment__enter_your_pin">Enter your PIN</string> <string name="RegistrationLockFragment__enter_your_pin">Enter your PIN</string>
<string name="KbsLockFragment__enter_the_pin_you_created">Enter the PIN you created for your account. This is different from your SMS verification code.</string> <string name="RegistrationLockFragment__enter_the_pin_you_created">Enter the PIN you created for your account. This is different from your SMS verification code.</string>
<string name="KbsLockFragment__enter_alphanumeric_pin">Enter alphanumeric PIN</string> <string name="RegistrationLockFragment__enter_alphanumeric_pin">Enter alphanumeric PIN</string>
<string name="KbsLockFragment__enter_numeric_pin">Enter numeric PIN</string> <string name="RegistrationLockFragment__enter_numeric_pin">Enter numeric PIN</string>
<string name="KbsLockFragment__next">Next</string> <string name="RegistrationLockFragment__next">Next</string>
<string name="KbsLockFragment__incorrect_pin_try_again">Incorrect PIN. Try again.</string> <string name="RegistrationLockFragment__incorrect_pin_try_again">Incorrect PIN. Try again.</string>
<string name="KbsLockFragment__incorrect_pin_d_attempts_remaining">Incorrect PIN. %1$d attempts remaining.</string> <string name="RegistrationLockFragment__forgot_pin">Forgot PIN?</string>
<string name="KbsLockFragment__forgot_pin">Forgot PIN?</string> <string name="RegistrationLockFragment__incorrect_pin">Incorrect PIN</string>
<string name="KbsLockFragment__incorrect_pin">Incorrect PIN</string> <string name="RegistrationLockFragment__forgot_your_pin">Forgot your PIN?</string>
<string name="KbsLockFragment__you_have_d_attempts_remaining">You have %1$d attempts remaining. If you run out of attempts your account will be locked for %2$d days. After %3$d days of inactivity, you can re-register without your PIN. Your account will be wiped and all content deleted.</string> <string name="RegistrationLockFragment__not_many_tries_left">Not many tries left!</string>
<string name="KbsLockFragment__forgot_your_pin">Forgot your PIN?</string>
<string name="KbsLockFragment__for_your_privacy_and_security_there_is_no_way_to_recover">For your privacy and security, there is no way to recover your PIN. If you can\'t remember your PIN, you can re-verify with SMS after %1$d days of inactivity. In this case, your account will be wiped and all content deleted.</string> <plurals name="RegistrationLockFragment__for_your_privacy_and_security_there_is_no_way_to_recover">
<item quantity="one">For your privacy and security, there is no way to recover your PIN. If you can\'t remember your PIN, you can re-verify with SMS after %1$d day of inactivity. In this case, your account will be wiped and all content deleted.</item>
<item quantity="other">For your privacy and security, there is no way to recover your PIN. If you can\'t remember your PIN, you can re-verify with SMS after %1$d days of inactivity. In this case, your account will be wiped and all content deleted.</item>
</plurals>
<plurals name="RegistrationLockFragment__incorrect_pin_d_attempts_remaining">
<item quantity="one">Incorrect PIN. %1$d attempt remaining.</item>
<item quantity="other">Incorrect PIN. %1$d attempts remaining.</item>
</plurals>
<plurals name="RegistrationLockFragment__if_you_run_out_of_attempts_your_account_will_be_locked_for_d_days">
<item quantity="one">If you run out of attempts your account will be locked for %1$d day. After %1$d day of inactivity, you can re-register without your PIN. Your account will be wiped and all content deleted.</item>
<item quantity="other">If you run out of attempts your account will be locked for %1$d days. After %1$d days of inactivity, you can re-register without your PIN. Your account will be wiped and all content deleted.</item>
</plurals>
<plurals name="RegistrationLockFragment__you_have_d_attempts_remaining">
<item quantity="one">You have %1$d attempt remaining.</item>
<item quantity="other">You have %1$d attempts remaining.</item>
</plurals>
<plurals name="RegistrationLockFragment__d_attempts_remaining">
<item quantity="one">%1$d attempt remaining.</item>
<item quantity="other">%1$d attempts remaining.</item>
</plurals>
<!-- KBS Megaphone --> <!-- KBS Megaphone -->
<string name="KbsMegaphone__create_a_pin">Create a PIN</string> <string name="KbsMegaphone__create_a_pin">Create a PIN</string>