Bring KBS fragment source into RegistrationLockFragment and handle account locked.
This commit is contained in:
parent
fb82420376
commit
1ea6838db6
10 changed files with 306 additions and 597 deletions
|
@ -31,7 +31,6 @@ import org.thoughtcrime.securesms.registration.service.CodeVerificationRequest;
|
|||
import org.thoughtcrime.securesms.registration.service.RegistrationCodeRequest;
|
||||
import org.thoughtcrime.securesms.registration.service.RegistrationService;
|
||||
import org.thoughtcrime.securesms.registration.viewmodel.RegistrationViewModel;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener;
|
||||
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
|
||||
|
||||
|
@ -122,30 +121,38 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onIncorrectRegistrationLockPin(long timeRemaining, String storageCredentials) {
|
||||
model.setStorageCredentials(storageCredentials);
|
||||
public void onV1RegistrationLockPinRequiredOrIncorrect(long timeRemaining) {
|
||||
model.setTimeRemaining(timeRemaining);
|
||||
keyboard.displayLocked().addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean r) {
|
||||
if (FeatureFlags.pinsForAll()) {
|
||||
Navigation.findNavController(requireView())
|
||||
.navigate(EnterCodeFragmentDirections.actionRequireKbsLockPin(timeRemaining));
|
||||
} else {
|
||||
Navigation.findNavController(requireView())
|
||||
.navigate(EnterCodeFragmentDirections.actionRequireRegistrationLockPin(timeRemaining));
|
||||
}
|
||||
Navigation.findNavController(requireView())
|
||||
.navigate(EnterCodeFragmentDirections.actionRequireKbsLockPin(timeRemaining));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIncorrectKbsRegistrationLockPin(@NonNull TokenResponse triesRemaining) {
|
||||
// Unexpected, because at this point, no pin has been provided by the user.
|
||||
throw new AssertionError();
|
||||
public void onKbsRegistrationLockPinRequired(long timeRemaining, @NonNull TokenResponse tokenResponse, @NonNull String kbsStorageCredentials) {
|
||||
model.setTimeRemaining(timeRemaining);
|
||||
model.setStorageCredentials(kbsStorageCredentials);
|
||||
model.setKeyBackupCurrentToken(tokenResponse);
|
||||
keyboard.displayLocked().addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean r) {
|
||||
Navigation.findNavController(requireView())
|
||||
.navigate(EnterCodeFragmentDirections.actionRequireKbsLockPin(timeRemaining));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTooManyAttempts() {
|
||||
public void onIncorrectKbsRegistrationLockPin(@NonNull TokenResponse tokenResponse) {
|
||||
throw new AssertionError("Unexpected, user has made no pin guesses");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRateLimited() {
|
||||
keyboard.displayFailure().addListener(new AssertedSuccessListener<Boolean>() {
|
||||
@Override
|
||||
public void onSuccess(Boolean r) {
|
||||
|
@ -163,6 +170,14 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKbsAccountLocked(long timeRemaining) {
|
||||
model.setTimeRemaining(timeRemaining);
|
||||
RegistrationLockFragmentDirections.ActionAccountLocked action = RegistrationLockFragmentDirections.actionAccountLocked(timeRemaining);
|
||||
|
||||
Navigation.findNavController(requireView()).navigate(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
Toast.makeText(requireContext(), R.string.RegistrationActivity_error_connecting_to_service, Toast.LENGTH_LONG).show();
|
||||
|
|
|
@ -1,221 +0,0 @@
|
|||
package org.thoughtcrime.securesms.registration.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import com.dd.CircularProgressButton;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.lock.v2.KbsKeyboardType;
|
||||
import org.thoughtcrime.securesms.registration.service.CodeVerificationRequest;
|
||||
import org.thoughtcrime.securesms.registration.service.RegistrationService;
|
||||
import org.thoughtcrime.securesms.registration.viewmodel.RegistrationViewModel;
|
||||
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class KbsLockFragment extends BaseRegistrationFragment {
|
||||
|
||||
private EditText pinEntry;
|
||||
private CircularProgressButton pinButton;
|
||||
private TextView errorLabel;
|
||||
private TextView keyboardToggle;
|
||||
private long timeRemaining;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.kbs_lock_fragment, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
setDebugLogSubmitMultiTapView(view.findViewById(R.id.kbs_lock_pin_title));
|
||||
|
||||
pinEntry = view.findViewById(R.id.kbs_lock_pin_input);
|
||||
pinButton = view.findViewById(R.id.kbs_lock_pin_confirm);
|
||||
errorLabel = view.findViewById(R.id.kbs_lock_pin_input_label);
|
||||
keyboardToggle = view.findViewById(R.id.kbs_lock_keyboard_toggle);
|
||||
|
||||
View pinForgotButton = view.findViewById(R.id.kbs_lock_forgot_pin);
|
||||
|
||||
timeRemaining = KbsLockFragmentArgs.fromBundle(requireArguments()).getTimeRemaining();
|
||||
|
||||
pinForgotButton.setOnClickListener(v -> handleForgottenPin(timeRemaining));
|
||||
|
||||
pinEntry.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||
pinEntry.setOnEditorActionListener((v, actionId, event) -> {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
hideKeyboard(requireContext(), v);
|
||||
handlePinEntry();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
pinButton.setOnClickListener((v) -> {
|
||||
hideKeyboard(requireContext(), pinEntry);
|
||||
handlePinEntry();
|
||||
});
|
||||
|
||||
keyboardToggle.setOnClickListener((v) -> {
|
||||
KbsKeyboardType keyboardType = getPinEntryKeyboardType();
|
||||
|
||||
updateKeyboard(keyboardType);
|
||||
keyboardToggle.setText(resolveKeyboardToggleText(keyboardType));
|
||||
});
|
||||
|
||||
RegistrationViewModel model = getModel();
|
||||
model.getTokenResponseCredentialsPair().observe(getViewLifecycleOwner(), pair -> {
|
||||
if (pair.first().getTries() == 0) {
|
||||
lockAccount();
|
||||
}
|
||||
});
|
||||
|
||||
model.onRegistrationLockFragmentCreate();
|
||||
}
|
||||
|
||||
private KbsKeyboardType getPinEntryKeyboardType() {
|
||||
boolean isNumeric = (pinEntry.getImeOptions() & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_NUMBER;
|
||||
|
||||
return isNumeric ? KbsKeyboardType.NUMERIC : KbsKeyboardType.ALPHA_NUMERIC;
|
||||
}
|
||||
|
||||
private void handlePinEntry() {
|
||||
final String pin = pinEntry.getText().toString();
|
||||
|
||||
if (TextUtils.isEmpty(pin) || TextUtils.isEmpty(pin.replace(" ", ""))) {
|
||||
Toast.makeText(requireContext(), R.string.RegistrationActivity_you_must_enter_your_registration_lock_PIN, Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
RegistrationViewModel model = getModel();
|
||||
RegistrationService registrationService = RegistrationService.getInstance(model.getNumber().getE164Number(), model.getRegistrationSecret());
|
||||
String storageCredentials = model.getBasicStorageCredentials();
|
||||
TokenResponse tokenResponse = model.getKeyBackupCurrentToken();
|
||||
|
||||
setSpinning(pinButton);
|
||||
|
||||
registrationService.verifyAccount(requireActivity(),
|
||||
model.getFcmToken(),
|
||||
model.getTextCodeEntered(),
|
||||
pin, storageCredentials, tokenResponse,
|
||||
|
||||
new CodeVerificationRequest.VerifyCallback() {
|
||||
|
||||
@Override
|
||||
public void onSuccessfulRegistration() {
|
||||
cancelSpinning(pinButton);
|
||||
SignalStore.kbsValues().setKeyboardType(getPinEntryKeyboardType());
|
||||
|
||||
Navigation.findNavController(requireView()).navigate(KbsLockFragmentDirections.actionSuccessfulRegistration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIncorrectRegistrationLockPin(long timeRemaining, String storageCredentials) {
|
||||
model.setStorageCredentials(storageCredentials);
|
||||
cancelSpinning(pinButton);
|
||||
|
||||
pinEntry.setText("");
|
||||
errorLabel.setText(R.string.KbsLockFragment__incorrect_pin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIncorrectKbsRegistrationLockPin(@NonNull TokenResponse tokenResponse) {
|
||||
cancelSpinning(pinButton);
|
||||
|
||||
model.setKeyBackupCurrentToken(tokenResponse);
|
||||
|
||||
int triesRemaining = tokenResponse.getTries();
|
||||
|
||||
if (triesRemaining == 0) {
|
||||
lockAccount();
|
||||
return;
|
||||
}
|
||||
|
||||
if (triesRemaining == 3) {
|
||||
long daysRemaining = getLockoutDays(timeRemaining);
|
||||
|
||||
new AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.KbsLockFragment__incorrect_pin)
|
||||
.setMessage(getString(R.string.KbsLockFragment__you_have_d_attempts_remaining, triesRemaining, daysRemaining, daysRemaining))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
if (triesRemaining > 5) {
|
||||
errorLabel.setText(R.string.KbsLockFragment__incorrect_pin_try_again);
|
||||
} else {
|
||||
errorLabel.setText(getString(R.string.KbsLockFragment__incorrect_pin_d_attempts_remaining, triesRemaining));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTooManyAttempts() {
|
||||
cancelSpinning(pinButton);
|
||||
|
||||
new AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.RegistrationActivity_too_many_attempts)
|
||||
.setMessage(R.string.RegistrationActivity_you_have_made_too_many_incorrect_registration_lock_pin_attempts_please_try_again_in_a_day)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
cancelSpinning(pinButton);
|
||||
|
||||
Toast.makeText(requireContext(), R.string.RegistrationActivity_error_connecting_to_service, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleForgottenPin(long timeRemainingMs) {
|
||||
new AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.KbsLockFragment__forgot_your_pin)
|
||||
.setMessage(getString(R.string.KbsLockFragment__for_your_privacy_and_security_there_is_no_way_to_recover, getLockoutDays(timeRemainingMs)))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private long getLockoutDays(long timeRemainingMs) {
|
||||
return TimeUnit.MILLISECONDS.toDays(timeRemainingMs) + 1;
|
||||
}
|
||||
|
||||
private void lockAccount() {
|
||||
KbsLockFragmentDirections.ActionAccountLocked action = KbsLockFragmentDirections.actionAccountLocked(timeRemaining);
|
||||
|
||||
Navigation.findNavController(requireView()).navigate(action);
|
||||
}
|
||||
|
||||
private void updateKeyboard(@NonNull KbsKeyboardType keyboard) {
|
||||
boolean isAlphaNumeric = keyboard == KbsKeyboardType.ALPHA_NUMERIC;
|
||||
|
||||
pinEntry.setInputType(isAlphaNumeric ? InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
: InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
|
||||
}
|
||||
|
||||
private @StringRes int resolveKeyboardToggleText(@NonNull KbsKeyboardType keyboard) {
|
||||
if (keyboard == KbsKeyboardType.ALPHA_NUMERIC) {
|
||||
return R.string.KbsLockFragment__enter_alphanumeric_pin;
|
||||
} else {
|
||||
return R.string.KbsLockFragment__enter_numeric_pin;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,6 @@ import androidx.navigation.ActivityNavigator;
|
|||
|
||||
import org.thoughtcrime.securesms.MainActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
||||
import org.thoughtcrime.securesms.lock.v2.PinUtil;
|
||||
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity;
|
||||
|
|
|
@ -1,32 +1,33 @@
|
|||
package org.thoughtcrime.securesms.registration.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import com.dd.CircularProgressButton;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.lock.v2.KbsKeyboardType;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.registration.service.CodeVerificationRequest;
|
||||
import org.thoughtcrime.securesms.registration.service.RegistrationService;
|
||||
import org.thoughtcrime.securesms.registration.viewmodel.RegistrationViewModel;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
||||
|
@ -35,11 +36,12 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
|||
|
||||
private EditText pinEntry;
|
||||
private CircularProgressButton pinButton;
|
||||
private TextView errorLabel;
|
||||
private TextView keyboardToggle;
|
||||
private long timeRemaining;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_registration_lock, container, false);
|
||||
}
|
||||
|
||||
|
@ -47,39 +49,19 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
|||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
setDebugLogSubmitMultiTapView(view.findViewById(R.id.verify_header));
|
||||
setDebugLogSubmitMultiTapView(view.findViewById(R.id.kbs_lock_pin_title));
|
||||
|
||||
pinEntry = view.findViewById(R.id.pin);
|
||||
pinButton = view.findViewById(R.id.pinButton);
|
||||
pinEntry = view.findViewById(R.id.kbs_lock_pin_input);
|
||||
pinButton = view.findViewById(R.id.kbs_lock_pin_confirm);
|
||||
errorLabel = view.findViewById(R.id.kbs_lock_pin_input_label);
|
||||
keyboardToggle = view.findViewById(R.id.kbs_lock_keyboard_toggle);
|
||||
|
||||
View clarificationLabel = view.findViewById(R.id.clarification_label);
|
||||
View subHeader = view.findViewById(R.id.verify_subheader);
|
||||
View pinForgotButton = view.findViewById(R.id.forgot_button);
|
||||
|
||||
String code = getModel().getTextCodeEntered();
|
||||
View pinForgotButton = view.findViewById(R.id.kbs_lock_forgot_pin);
|
||||
|
||||
timeRemaining = RegistrationLockFragmentArgs.fromBundle(requireArguments()).getTimeRemaining();
|
||||
|
||||
pinForgotButton.setOnClickListener(v -> handleForgottenPin(timeRemaining));
|
||||
|
||||
pinEntry.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) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
boolean matchesTextCode = s != null && s.toString().equals(code);
|
||||
clarificationLabel.setVisibility(matchesTextCode ? View.VISIBLE : View.INVISIBLE);
|
||||
subHeader.setVisibility(matchesTextCode ? View.INVISIBLE : View.VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
pinEntry.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||
pinEntry.setOnEditorActionListener((v, actionId, event) -> {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
|
@ -95,35 +77,21 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
|||
handlePinEntry();
|
||||
});
|
||||
|
||||
RegistrationViewModel model = getModel();
|
||||
model.getTokenResponseCredentialsPair()
|
||||
.observe(this, pair -> {
|
||||
TokenResponse token = pair.first();
|
||||
String credentials = pair.second();
|
||||
updateContinueText(token, credentials);
|
||||
});
|
||||
keyboardToggle.setOnClickListener((v) -> {
|
||||
KbsKeyboardType keyboardType = getPinEntryKeyboardType();
|
||||
|
||||
model.onRegistrationLockFragmentCreate();
|
||||
updateKeyboard(keyboardType);
|
||||
keyboardToggle.setText(resolveKeyboardToggleText(keyboardType));
|
||||
});
|
||||
|
||||
getModel().getTimeRemaining()
|
||||
.observe(getViewLifecycleOwner(), t -> timeRemaining = t);
|
||||
}
|
||||
|
||||
private void updateContinueText(@Nullable TokenResponse tokenResponse, @Nullable String storageCredentials) {
|
||||
if (tokenResponse == null) {
|
||||
if (storageCredentials == null) {
|
||||
pinButton.setIdleText(getString(R.string.RegistrationActivity_continue));
|
||||
} else {
|
||||
// TODO: This is the case where we can determine they are locked out
|
||||
// no token, but do have storage credentials. Might want to change text.
|
||||
pinButton.setIdleText(getString(R.string.RegistrationActivity_continue));
|
||||
}
|
||||
} else {
|
||||
int triesRemaining = tokenResponse.getTries();
|
||||
if (triesRemaining == 1) {
|
||||
pinButton.setIdleText(getString(R.string.RegistrationActivity_continue_last_attempt));
|
||||
} else {
|
||||
pinButton.setIdleText(getString(R.string.RegistrationActivity_continue_d_attempts_left, triesRemaining));
|
||||
}
|
||||
}
|
||||
pinButton.setText(pinButton.getIdleText());
|
||||
private KbsKeyboardType getPinEntryKeyboardType() {
|
||||
boolean isNumeric = (pinEntry.getImeOptions() & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_NUMBER;
|
||||
|
||||
return isNumeric ? KbsKeyboardType.NUMERIC : KbsKeyboardType.ALPHA_NUMERIC;
|
||||
}
|
||||
|
||||
private void handlePinEntry() {
|
||||
|
@ -134,58 +102,79 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
|||
return;
|
||||
}
|
||||
|
||||
RegistrationViewModel model = getModel();
|
||||
RegistrationService registrationService = RegistrationService.getInstance(model.getNumber().getE164Number(), model.getRegistrationSecret());
|
||||
String storageCredentials = model.getBasicStorageCredentials();
|
||||
TokenResponse tokenResponse = model.getKeyBackupCurrentToken();
|
||||
RegistrationViewModel model = getModel();
|
||||
RegistrationService registrationService = RegistrationService.getInstance(model.getNumber().getE164Number(), model.getRegistrationSecret());
|
||||
TokenResponse tokenResponse = model.getKeyBackupCurrentToken();
|
||||
String basicStorageCredentials = model.getBasicStorageCredentials();
|
||||
|
||||
setSpinning(pinButton);
|
||||
|
||||
registrationService.verifyAccount(requireActivity(),
|
||||
model.getFcmToken(),
|
||||
model.getTextCodeEntered(),
|
||||
pin, storageCredentials, tokenResponse,
|
||||
pin,
|
||||
basicStorageCredentials,
|
||||
tokenResponse,
|
||||
|
||||
new CodeVerificationRequest.VerifyCallback() {
|
||||
|
||||
@Override
|
||||
public void onSuccessfulRegistration() {
|
||||
cancelSpinning(pinButton);
|
||||
SignalStore.kbsValues().setKeyboardType(getPinEntryKeyboardType());
|
||||
|
||||
Navigation.findNavController(requireView()).navigate(RegistrationLockFragmentDirections.actionSuccessfulRegistration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIncorrectRegistrationLockPin(long timeRemaining, String storageCredentials) {
|
||||
model.setStorageCredentials(storageCredentials);
|
||||
cancelSpinning(pinButton);
|
||||
public void onV1RegistrationLockPinRequiredOrIncorrect(long timeRemaining) {
|
||||
getModel().setTimeRemaining(timeRemaining);
|
||||
|
||||
pinEntry.setText("");
|
||||
Toast.makeText(requireContext(), R.string.RegistrationActivity_incorrect_registration_lock_pin, Toast.LENGTH_LONG).show();
|
||||
cancelSpinning(pinButton);
|
||||
pinEntry.getText().clear();
|
||||
|
||||
errorLabel.setText(R.string.KbsLockFragment__incorrect_pin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKbsRegistrationLockPinRequired(long timeRemaining, @NonNull TokenResponse kbsTokenResponse, @NonNull String kbsStorageCredentials) {
|
||||
throw new AssertionError("Not expected after a pin guess");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIncorrectKbsRegistrationLockPin(@NonNull TokenResponse tokenResponse) {
|
||||
cancelSpinning(pinButton);
|
||||
pinEntry.getText().clear();
|
||||
|
||||
model.setKeyBackupCurrentToken(tokenResponse);
|
||||
|
||||
int triesRemaining = tokenResponse.getTries();
|
||||
|
||||
if (triesRemaining == 0) {
|
||||
handleForgottenPin(timeRemaining);
|
||||
Log.w(TAG, "Account locked. User out of attempts on KBS.");
|
||||
lockAccount(timeRemaining);
|
||||
return;
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.RegistrationActivity_pin_incorrect)
|
||||
.setMessage(getString(R.string.RegistrationActivity_you_have_d_tries_remaining, triesRemaining))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
if (triesRemaining == 3) {
|
||||
long daysRemaining = getLockoutDays(timeRemaining);
|
||||
|
||||
new AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.KbsLockFragment__incorrect_pin)
|
||||
.setMessage(getString(R.string.KbsLockFragment__you_have_d_attempts_remaining, triesRemaining, daysRemaining, daysRemaining))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
if (triesRemaining > 5) {
|
||||
errorLabel.setText(R.string.KbsLockFragment__incorrect_pin_try_again);
|
||||
} else {
|
||||
errorLabel.setText(getString(R.string.KbsLockFragment__incorrect_pin_d_attempts_remaining, triesRemaining));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTooManyAttempts() {
|
||||
public void onRateLimited() {
|
||||
cancelSpinning(pinButton);
|
||||
|
||||
new AlertDialog.Builder(requireContext())
|
||||
|
@ -195,6 +184,13 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
|||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKbsAccountLocked(long timeRemaining) {
|
||||
getModel().setTimeRemaining(timeRemaining);
|
||||
|
||||
lockAccount(timeRemaining);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
cancelSpinning(pinButton);
|
||||
|
@ -206,9 +202,34 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
|
|||
|
||||
private void handleForgottenPin(long timeRemainingMs) {
|
||||
new AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.RegistrationActivity_oh_no)
|
||||
.setMessage(getString(R.string.RegistrationActivity_registration_of_this_phone_number_will_be_possible_without_your_registration_lock_pin_after_seven_days_have_passed, (TimeUnit.MILLISECONDS.toDays(timeRemainingMs) + 1)))
|
||||
.setTitle(R.string.KbsLockFragment__forgot_your_pin)
|
||||
.setMessage(getString(R.string.KbsLockFragment__for_your_privacy_and_security_there_is_no_way_to_recover, getLockoutDays(timeRemainingMs)))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private static long getLockoutDays(long timeRemainingMs) {
|
||||
return TimeUnit.MILLISECONDS.toDays(timeRemainingMs) + 1;
|
||||
}
|
||||
|
||||
private void lockAccount(long timeRemaining) {
|
||||
RegistrationLockFragmentDirections.ActionAccountLocked action = RegistrationLockFragmentDirections.actionAccountLocked(timeRemaining);
|
||||
|
||||
Navigation.findNavController(requireView()).navigate(action);
|
||||
}
|
||||
|
||||
private void updateKeyboard(@NonNull KbsKeyboardType keyboard) {
|
||||
boolean isAlphaNumeric = keyboard == KbsKeyboardType.ALPHA_NUMERIC;
|
||||
|
||||
pinEntry.setInputType(isAlphaNumeric ? InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
: InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
|
||||
}
|
||||
|
||||
private @StringRes static int resolveKeyboardToggleText(@NonNull KbsKeyboardType keyboard) {
|
||||
if (keyboard == KbsKeyboardType.ALPHA_NUMERIC) {
|
||||
return R.string.KbsLockFragment__enter_alphanumeric_pin;
|
||||
} else {
|
||||
return R.string.KbsLockFragment__enter_numeric_pin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,16 +53,12 @@ public final class CodeVerificationRequest {
|
|||
|
||||
private static final String TAG = Log.tag(CodeVerificationRequest.class);
|
||||
|
||||
static TokenResponse getToken(@Nullable String basicStorageCredentials) throws IOException {
|
||||
if (basicStorageCredentials == null) return null;
|
||||
return ApplicationDependencies.getKeyBackupService().getToken(basicStorageCredentials);
|
||||
}
|
||||
|
||||
private enum Result {
|
||||
SUCCESS,
|
||||
PIN_LOCKED,
|
||||
KBS_WRONG_PIN,
|
||||
RATE_LIMITED,
|
||||
KBS_ACCOUNT_LOCKED,
|
||||
ERROR
|
||||
}
|
||||
|
||||
|
@ -87,17 +83,39 @@ public final class CodeVerificationRequest {
|
|||
{
|
||||
new AsyncTask<Void, Void, Result>() {
|
||||
|
||||
private volatile LockedException lockedException;
|
||||
private volatile KeyBackupSystemWrongPinException keyBackupSystemWrongPinException;
|
||||
private volatile LockedException lockedException;
|
||||
private volatile TokenResponse kbsToken;
|
||||
|
||||
@Override
|
||||
protected Result doInBackground(Void... voids) {
|
||||
final boolean pinSupplied = pin != null;
|
||||
final boolean tryKbs = kbsTokenResponse != null;
|
||||
|
||||
try {
|
||||
verifyAccount(context, credentials, code, pin, basicStorageCredentials, kbsTokenResponse, fcmToken);
|
||||
kbsToken = kbsTokenResponse;
|
||||
verifyAccount(context, credentials, code, pin, kbsTokenResponse, basicStorageCredentials, fcmToken);
|
||||
return Result.SUCCESS;
|
||||
} catch (KeyBackupSystemWrongPinException e) {
|
||||
kbsToken = e.getTokenResponse();
|
||||
return Result.KBS_WRONG_PIN;
|
||||
} catch (LockedException e) {
|
||||
if (pinSupplied && tryKbs) {
|
||||
throw new AssertionError("KBS Pin appeared to matched but reg lock still failed!");
|
||||
}
|
||||
|
||||
Log.w(TAG, e);
|
||||
lockedException = e;
|
||||
if (e.getBasicStorageCredentials() != null) {
|
||||
try {
|
||||
kbsToken = getToken(e.getBasicStorageCredentials());
|
||||
if (kbsToken == null || kbsToken.getTries() == 0) {
|
||||
return Result.KBS_ACCOUNT_LOCKED;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Log.w(TAG, e);
|
||||
return Result.ERROR;
|
||||
}
|
||||
}
|
||||
return Result.PIN_LOCKED;
|
||||
} catch (RateLimitException e) {
|
||||
Log.w(TAG, e);
|
||||
|
@ -105,9 +123,6 @@ public final class CodeVerificationRequest {
|
|||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return Result.ERROR;
|
||||
} catch (KeyBackupSystemWrongPinException e) {
|
||||
keyBackupSystemWrongPinException = e;
|
||||
return Result.KBS_WRONG_PIN;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,22 +134,41 @@ public final class CodeVerificationRequest {
|
|||
callback.onSuccessfulRegistration();
|
||||
break;
|
||||
case PIN_LOCKED:
|
||||
callback.onIncorrectRegistrationLockPin(lockedException.getTimeRemaining(), lockedException.getBasicStorageCredentials());
|
||||
if (kbsToken != null) {
|
||||
if (lockedException.getBasicStorageCredentials() == null) {
|
||||
throw new AssertionError("KBS Token set, but no storage credentials supplied.");
|
||||
}
|
||||
Log.w(TAG, "Reg Locked: V2 pin needed for registration");
|
||||
callback.onKbsRegistrationLockPinRequired(lockedException.getTimeRemaining(), kbsToken, lockedException.getBasicStorageCredentials());
|
||||
} else {
|
||||
Log.w(TAG, "Reg Locked: V1 pin needed for registration");
|
||||
callback.onV1RegistrationLockPinRequiredOrIncorrect(lockedException.getTimeRemaining());
|
||||
}
|
||||
break;
|
||||
case RATE_LIMITED:
|
||||
callback.onTooManyAttempts();
|
||||
callback.onRateLimited();
|
||||
break;
|
||||
case ERROR:
|
||||
callback.onError();
|
||||
break;
|
||||
case KBS_WRONG_PIN:
|
||||
callback.onIncorrectKbsRegistrationLockPin(keyBackupSystemWrongPinException.getTokenResponse());
|
||||
Log.w(TAG, "KBS Pin was wrong");
|
||||
callback.onIncorrectKbsRegistrationLockPin(kbsToken);
|
||||
break;
|
||||
case KBS_ACCOUNT_LOCKED:
|
||||
Log.w(TAG, "KBS Account is locked");
|
||||
callback.onKbsAccountLocked(lockedException.getTimeRemaining());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private static TokenResponse getToken(@Nullable String basicStorageCredentials) throws IOException {
|
||||
if (basicStorageCredentials == null) return null;
|
||||
return ApplicationDependencies.getKeyBackupService().getToken(basicStorageCredentials);
|
||||
}
|
||||
|
||||
private static void handleSuccessfulRegistration(@NonNull Context context) {
|
||||
JobManager jobManager = ApplicationDependencies.getJobManager();
|
||||
jobManager.add(new DirectoryRefreshJob(false));
|
||||
|
@ -148,11 +182,12 @@ public final class CodeVerificationRequest {
|
|||
@NonNull Credentials credentials,
|
||||
@NonNull String code,
|
||||
@Nullable String pin,
|
||||
@Nullable String basicStorageCredentials,
|
||||
@Nullable TokenResponse kbsTokenResponse,
|
||||
@Nullable String kbsStorageCredentials,
|
||||
@Nullable String fcmToken)
|
||||
throws IOException, KeyBackupSystemWrongPinException
|
||||
{
|
||||
boolean isV2KbsPin = kbsTokenResponse != null;
|
||||
int registrationId = KeyHelper.generateRegistrationId(false);
|
||||
byte[] unidentifiedAccessKey = UnidentifiedAccessUtil.getSelfUnidentifiedAccessKey(context);
|
||||
boolean universalUnidentifiedAccess = TextSecurePreferences.isUniversalUnidentifiedAccess(context);
|
||||
|
@ -161,10 +196,10 @@ public final class CodeVerificationRequest {
|
|||
SessionUtil.archiveAllSessions(context);
|
||||
|
||||
SignalServiceAccountManager accountManager = AccountManagerFactory.createUnauthenticated(context, credentials.getE164number(), credentials.getPassword());
|
||||
RegistrationLockData kbsData = restoreMasterKey(pin, basicStorageCredentials, kbsTokenResponse);
|
||||
RegistrationLockData kbsData = isV2KbsPin ? restoreMasterKey(pin, kbsStorageCredentials, kbsTokenResponse) : null;
|
||||
String registrationLock = kbsData != null ? kbsData.getMasterKey().deriveRegistrationLock() : null;
|
||||
boolean present = fcmToken != null;
|
||||
String pinForServer = basicStorageCredentials == null ? pin : null;
|
||||
String pinForServer = isV2KbsPin ? null : pin;
|
||||
|
||||
UUID uuid = accountManager.verifyAccountWithCode(code, null, registrationId, !present,
|
||||
pinForServer, registrationLock,
|
||||
|
@ -251,14 +286,13 @@ public final class CodeVerificationRequest {
|
|||
|
||||
private static @Nullable RegistrationLockData restoreMasterKey(@Nullable String pin,
|
||||
@Nullable String basicStorageCredentials,
|
||||
@Nullable TokenResponse tokenResponse)
|
||||
@NonNull TokenResponse tokenResponse)
|
||||
throws IOException, KeyBackupSystemWrongPinException
|
||||
{
|
||||
if (pin == null) return null;
|
||||
|
||||
if (basicStorageCredentials == null) {
|
||||
Log.i(TAG, "No storage credentials supplied, pin is not on KBS");
|
||||
return null;
|
||||
throw new AssertionError("Cannot restore KBS key, no storage credentials supplied");
|
||||
}
|
||||
|
||||
KeyBackupService keyBackupService = ApplicationDependencies.getKeyBackupService();
|
||||
|
@ -290,13 +324,32 @@ public final class CodeVerificationRequest {
|
|||
void onSuccessfulRegistration();
|
||||
|
||||
/**
|
||||
* The account is locked with a V1 (non-KBS) pin.
|
||||
*
|
||||
* @param timeRemaining Time until pin expires and number can be reused.
|
||||
*/
|
||||
void onIncorrectRegistrationLockPin(long timeRemaining, String storageCredentials);
|
||||
void onV1RegistrationLockPinRequiredOrIncorrect(long timeRemaining);
|
||||
|
||||
/**
|
||||
* The account is locked with a V2 (KBS) pin. Called before any user pin guesses.
|
||||
*/
|
||||
void onKbsRegistrationLockPinRequired(long timeRemaining, @NonNull TokenResponse kbsTokenResponse, @NonNull String kbsStorageCredentials);
|
||||
|
||||
/**
|
||||
* The account is locked with a V2 (KBS) pin. Called after a user pin guess.
|
||||
* <p>
|
||||
* i.e. an attempt has likely been used.
|
||||
*/
|
||||
void onIncorrectKbsRegistrationLockPin(@NonNull TokenResponse kbsTokenResponse);
|
||||
|
||||
void onTooManyAttempts();
|
||||
/**
|
||||
* V2 (KBS) pin is set, but there is no data on KBS
|
||||
*
|
||||
* @param timeRemaining Time until pin expires and number can be reused.
|
||||
*/
|
||||
void onKbsAccountLocked(long timeRemaining);
|
||||
|
||||
void onRateLimited();
|
||||
|
||||
void onError();
|
||||
}
|
||||
|
|
|
@ -45,8 +45,4 @@ public final class RegistrationService {
|
|||
{
|
||||
CodeVerificationRequest.verifyAccount(activity, credentials, fcmToken, code, pin, basicStorageCredentials, tokenResponse, callback);
|
||||
}
|
||||
|
||||
public @Nullable TokenResponse getToken(@Nullable String basicStorageCredentials) throws IOException {
|
||||
return CodeVerificationRequest.getToken(basicStorageCredentials);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,15 +6,10 @@ import androidx.annotation.Nullable;
|
|||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.SavedStateHandle;
|
||||
import androidx.lifecycle.Transformations;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.registration.service.RegistrationService;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataPair;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
|
||||
import org.whispersystems.signalservice.internal.util.JsonUtil;
|
||||
|
||||
|
@ -34,8 +29,7 @@ public final class RegistrationViewModel extends ViewModel {
|
|||
private final MutableLiveData<Integer> successfulCodeRequestAttempts;
|
||||
private final MutableLiveData<LocalCodeRequestRateLimiter> requestLimiter;
|
||||
private final MutableLiveData<String> keyBackupcurrentTokenJson;
|
||||
private final LiveData<TokenResponse> keyBackupcurrentToken;
|
||||
private final LiveData<Pair<TokenResponse, String>> tokenResponseCredentialsPair;
|
||||
private final MutableLiveData<Long> timeRemaining;
|
||||
|
||||
public RegistrationViewModel(@NonNull SavedStateHandle savedStateHandle) {
|
||||
secret = loadValue(savedStateHandle, "REGISTRATION_SECRET", Util.getSecret(18));
|
||||
|
@ -49,19 +43,7 @@ public final class RegistrationViewModel extends ViewModel {
|
|||
successfulCodeRequestAttempts = savedStateHandle.getLiveData("SUCCESSFUL_CODE_REQUEST_ATTEMPTS", 0);
|
||||
requestLimiter = savedStateHandle.getLiveData("REQUEST_RATE_LIMITER", new LocalCodeRequestRateLimiter(60_000));
|
||||
keyBackupcurrentTokenJson = savedStateHandle.getLiveData("KBS_TOKEN");
|
||||
|
||||
keyBackupcurrentToken = Transformations.map(keyBackupcurrentTokenJson, json ->
|
||||
{
|
||||
if (json == null) return null;
|
||||
try {
|
||||
return JsonUtil.fromJson(json, TokenResponse.class);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
tokenResponseCredentialsPair = new LiveDataPair<>(keyBackupcurrentToken, basicStorageCredentials);
|
||||
timeRemaining = savedStateHandle.getLiveData("TIME_REMAINING", 0L);
|
||||
}
|
||||
|
||||
private static <T> T loadValue(@NonNull SavedStateHandle savedStateHandle, @NonNull String key, @NonNull T initialValue) {
|
||||
|
@ -179,26 +161,26 @@ public final class RegistrationViewModel extends ViewModel {
|
|||
}
|
||||
|
||||
public @Nullable TokenResponse getKeyBackupCurrentToken() {
|
||||
return keyBackupcurrentToken.getValue();
|
||||
String json = keyBackupcurrentTokenJson.getValue();
|
||||
if (json == null) return null;
|
||||
try {
|
||||
return JsonUtil.fromJson(json, TokenResponse.class);
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setKeyBackupCurrentToken(TokenResponse tokenResponse) {
|
||||
keyBackupcurrentTokenJson.setValue(tokenResponse == null ? null : JsonUtil.toJson(tokenResponse));
|
||||
String json = tokenResponse == null ? null : JsonUtil.toJson(tokenResponse);
|
||||
keyBackupcurrentTokenJson.setValue(json);
|
||||
}
|
||||
|
||||
public LiveData<Pair<TokenResponse, String>> getTokenResponseCredentialsPair() {
|
||||
return tokenResponseCredentialsPair;
|
||||
public LiveData<Long> getTimeRemaining() {
|
||||
return timeRemaining;
|
||||
}
|
||||
|
||||
public void onRegistrationLockFragmentCreate() {
|
||||
SimpleTask.run(() -> {
|
||||
RegistrationService registrationService = RegistrationService.getInstance(getNumber().getE164Number(), getRegistrationSecret());
|
||||
try {
|
||||
return registrationService.getToken(getBasicStorageCredentials());
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
}
|
||||
}, this::setKeyBackupCurrentToken);
|
||||
public void setTimeRemaining(long timeRemaining) {
|
||||
this.timeRemaining.setValue(timeRemaining);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,113 +1,95 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
tools:context=".registration.fragments.RegistrationLockFragment">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<TextView
|
||||
android:id="@+id/kbs_lock_pin_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp">
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/KbsLockFragment__enter_your_pin"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Title1"
|
||||
app:layout_constraintBottom_toTopOf="@id/kbs_lock_keyboard_toggle"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.20" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/clarification_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/registration_activity__the_registration_lock_pin_is_not_the_same_as_the_sms_verification_code_you_just_received_please_enter_the_pin_you_previously_configured_in_the_application"
|
||||
android:textColor="#73B7F0"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/verify_header"
|
||||
tools:visibility="visible" />
|
||||
<TextView
|
||||
android:id="@+id/kbs_lock_pin_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="27dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="27dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:minHeight="66dp"
|
||||
android:text="@string/KbsLockFragment__enter_the_pin_you_created"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="@color/core_grey_60"
|
||||
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/verify_header"
|
||||
style="@style/Signal.Text.Headline.Registration"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/RegistrationActivity_registration_lock_pin"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<EditText
|
||||
android:id="@+id/kbs_lock_pin_input"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:inputType="numberPassword"
|
||||
android:minWidth="210dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_description" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/verify_subheader"
|
||||
style="@style/Signal.Text.Body.Registration"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/RegistrationActivity_this_phone_number_has_registration_lock_enabled_please_enter_the_registration_lock_pin"
|
||||
app:layout_constraintTop_toBottomOf="@+id/verify_header"
|
||||
tools:layout_editor_absoluteX="0dp" />
|
||||
<TextView
|
||||
android:id="@+id/kbs_lock_pin_input_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_horizontal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_input"
|
||||
tools:text="@string/KbsLockFragment__incorrect_pin_try_again" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/forgot_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
android:padding="16dp"
|
||||
android:text="@string/registration_activity__forgot_pin"
|
||||
android:textColor="@color/blue_400"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/pinButton" />
|
||||
<Button
|
||||
android:id="@+id/kbs_lock_forgot_pin"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:text="@string/KbsLockFragment__forgot_pin"
|
||||
android:textColor="@color/signal_primary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_input" />
|
||||
|
||||
<com.dd.CircularProgressButton
|
||||
android:id="@+id/pinButton"
|
||||
style="@style/Button.Registration"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:cpb_textIdle="@string/RegistrationActivity_continue"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textInputLayout" />
|
||||
<Button
|
||||
android:id="@+id/kbs_lock_keyboard_toggle"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:textColor="@color/signal_primary"
|
||||
app:layout_constraintBottom_toTopOf="@id/kbs_lock_pin_confirm"
|
||||
tools:text="Create Alphanumeric Pin" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/textInputLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/clarification_label">
|
||||
<com.dd.CircularProgressButton
|
||||
android:id="@+id/kbs_lock_pin_confirm"
|
||||
style="@style/Button.Registration"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cpb_textIdle="@string/RegistrationActivity_continue"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/pin"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:hint="@string/registration_activity__registration_lock_pin"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="numberPassword" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,95 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/kbs_lock_pin_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/KbsLockFragment__enter_your_pin"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Title1"
|
||||
app:layout_constraintBottom_toTopOf="@id/kbs_lock_keyboard_toggle"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.20" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/kbs_lock_pin_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="27dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="27dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:minHeight="66dp"
|
||||
android:text="@string/KbsLockFragment__enter_the_pin_you_created"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="@color/core_grey_60"
|
||||
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_title" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/kbs_lock_pin_input"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:inputType="numberPassword"
|
||||
android:minWidth="210dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_description" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/kbs_lock_pin_input_label"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_horizontal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_input"
|
||||
tools:text="@string/KbsLockFragment__incorrect_pin_try_again" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/kbs_lock_forgot_pin"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:text="@string/KbsLockFragment__forgot_pin"
|
||||
android:textColor="@color/signal_primary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/kbs_lock_pin_input" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/kbs_lock_keyboard_toggle"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:textColor="@color/signal_primary"
|
||||
app:layout_constraintBottom_toTopOf="@id/kbs_lock_pin_confirm"
|
||||
tools:text="Create Alphanumeric Pin" />
|
||||
|
||||
<com.dd.CircularProgressButton
|
||||
android:id="@+id/kbs_lock_pin_confirm"
|
||||
style="@style/Button.Registration"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cpb_textIdle="@string/RegistrationActivity_continue"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -81,19 +81,9 @@
|
|||
android:label="fragment_enter_code"
|
||||
tools:layout="@layout/fragment_registration_enter_code">
|
||||
|
||||
<action
|
||||
android:id="@+id/action_requireRegistrationLockPin"
|
||||
app:destination="@id/registrationLockFragment"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:popUpTo="@+id/welcomeFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
|
||||
<action
|
||||
android:id="@+id/action_requireKbsLockPin"
|
||||
app:destination="@id/kbsLockFragment"
|
||||
app:destination="@id/registrationLockFragment"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
|
@ -119,18 +109,9 @@
|
|||
app:destination="@id/registrationCompletePlaceHolderFragment"
|
||||
app:popUpTo="@+id/welcomeFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/registrationLockFragment"
|
||||
android:name="org.thoughtcrime.securesms.registration.fragments.RegistrationLockFragment"
|
||||
android:label="fragment_registration_lock"
|
||||
tools:layout="@layout/fragment_registration_lock">
|
||||
|
||||
<action
|
||||
android:id="@+id/action_successfulRegistration"
|
||||
app:destination="@id/registrationCompletePlaceHolderFragment"
|
||||
android:id="@+id/action_accountLocked"
|
||||
app:destination="@id/accountLockedFragment"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
|
@ -138,17 +119,13 @@
|
|||
app:popUpTo="@+id/welcomeFragment"
|
||||
app:popUpToInclusive="true" />
|
||||
|
||||
<argument
|
||||
android:name="timeRemaining"
|
||||
app:argType="long" />
|
||||
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/kbsLockFragment"
|
||||
android:name="org.thoughtcrime.securesms.registration.fragments.KbsLockFragment"
|
||||
android:id="@+id/registrationLockFragment"
|
||||
android:name="org.thoughtcrime.securesms.registration.fragments.RegistrationLockFragment"
|
||||
android:label="fragment_kbs_lock"
|
||||
tools:layout="@layout/kbs_lock_fragment">
|
||||
tools:layout="@layout/fragment_registration_lock">
|
||||
|
||||
<action
|
||||
android:id="@+id/action_successfulRegistration"
|
||||
|
|
Loading…
Add table
Reference in a new issue