diff --git a/app/src/main/java/org/thoughtcrime/securesms/lock/RegistrationLockDialog.java b/app/src/main/java/org/thoughtcrime/securesms/lock/RegistrationLockDialog.java
index 23bc6b2523..0d8213f23b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/lock/RegistrationLockDialog.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/lock/RegistrationLockDialog.java
@@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.KeyBackupServicePinException;
+import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
import org.whispersystems.signalservice.api.RegistrationLockData;
import org.whispersystems.signalservice.api.kbs.HashedPin;
import org.whispersystems.signalservice.api.kbs.MasterKey;
@@ -305,7 +306,7 @@ public final class RegistrationLockDialog {
TextSecurePreferences.setRegistrationLockLastReminderTime(context, System.currentTimeMillis());
TextSecurePreferences.setRegistrationLockNextReminderInterval(context, RegistrationLockReminders.INITIAL_INTERVAL);
return true;
- } catch (IOException | UnauthenticatedResponseException | KeyBackupServicePinException e) {
+ } catch (IOException | UnauthenticatedResponseException | KeyBackupServicePinException | KeyBackupSystemNoDataException e) {
Log.w(TAG, e);
return false;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/lock/v2/ConfirmKbsPinRepository.java b/app/src/main/java/org/thoughtcrime/securesms/lock/v2/ConfirmKbsPinRepository.java
index fe893f9609..2e9168df67 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/lock/v2/ConfirmKbsPinRepository.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/lock/v2/ConfirmKbsPinRepository.java
@@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.KeyBackupServicePinException;
+import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
import org.whispersystems.signalservice.api.RegistrationLockData;
import org.whispersystems.signalservice.api.kbs.HashedPin;
import org.whispersystems.signalservice.api.kbs.MasterKey;
@@ -59,7 +60,7 @@ final class ConfirmKbsPinRepository {
ApplicationDependencies.getMegaphoneRepository().markFinished(Megaphones.Event.PINS_FOR_ALL);
return PinSetResult.SUCCESS;
- } catch (IOException | UnauthenticatedResponseException | KeyBackupServicePinException e) {
+ } catch (IOException | UnauthenticatedResponseException | KeyBackupServicePinException | KeyBackupSystemNoDataException e) {
Log.w(TAG, e);
return PinSetResult.FAILURE;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java
index 1003e81b5b..ca72416e34 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java
@@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.KeyBackupServicePinException;
+import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
import org.whispersystems.signalservice.api.RegistrationLockData;
import org.whispersystems.signalservice.api.kbs.HashedPin;
import org.whispersystems.signalservice.api.kbs.MasterKey;
@@ -55,7 +56,7 @@ public final class RegistrationPinV2MigrationJob extends BaseJob {
}
@Override
- protected void onRun() throws IOException, UnauthenticatedResponseException, KeyBackupServicePinException {
+ protected void onRun() throws IOException, UnauthenticatedResponseException, KeyBackupServicePinException, KeyBackupSystemNoDataException {
if (!TextSecurePreferences.isV1RegistrationLockEnabled(context)) {
Log.i(TAG, "Registration lock disabled");
return;
diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/AccountLockedFragment.java b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/AccountLockedFragment.java
index 9254a12bab..14543f52d0 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/AccountLockedFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/AccountLockedFragment.java
@@ -11,11 +11,12 @@ import android.widget.TextView;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
import org.thoughtcrime.securesms.R;
-public class AccountLockedFragment extends Fragment {
+import java.util.concurrent.TimeUnit;
+
+public class AccountLockedFragment extends BaseRegistrationFragment {
@Override
public @Nullable View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
@@ -24,14 +25,16 @@ public class AccountLockedFragment extends Fragment {
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
- AccountLockedFragmentArgs args = AccountLockedFragmentArgs.fromBundle(requireArguments());
+ super.onViewCreated(view, savedInstanceState);
TextView description = view.findViewById(R.id.account_locked_description);
- description.setText(getString(R.string.AccountLockedFragment__your_account_has_been_locked_to_protect_your_privacy, args.getTimeRemaining()));
+ getModel().getTimeRemaining().observe(getViewLifecycleOwner(),
+ t -> description.setText(getString(R.string.AccountLockedFragment__your_account_has_been_locked_to_protect_your_privacy, durationToDays(t)))
+ );
- view.findViewById(R.id.account_locked_next).setOnClickListener(this::onNextClicked);
- view.findViewById(R.id.account_locked_learn_more).setOnClickListener(this::onLearnMoreClicked);
+ view.findViewById(R.id.account_locked_next).setOnClickListener(v -> onNext());
+ view.findViewById(R.id.account_locked_learn_more).setOnClickListener(v -> learnMore());
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
@Override
@@ -41,16 +44,18 @@ public class AccountLockedFragment extends Fragment {
});
}
- private void onNextClicked(@NonNull View unused) {
- onNext();
+ private void learnMore() {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(getString(R.string.AccountLockedFragment__learn_more_url)));
+ startActivity(intent);
}
- private void onLearnMoreClicked(@NonNull View unused) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
+ private static long durationToDays(Long duration) {
+ return duration != null ? getLockoutDays(duration) : 7;
+ }
- intent.setData(Uri.parse(getString(R.string.AccountLockedFragment__learn_more_url)));
-
- startActivity(intent);
+ private static int getLockoutDays(long timeRemainingMs) {
+ return (int) TimeUnit.MILLISECONDS.toDays(timeRemainingMs) + 1;
}
private void onNext() {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/EnterCodeFragment.java b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/EnterCodeFragment.java
index 0641458004..fe7728b7dc 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/EnterCodeFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/EnterCodeFragment.java
@@ -171,11 +171,11 @@ 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);
+ public void onKbsAccountLocked(@Nullable Long timeRemaining) {
+ if (timeRemaining != null) {
+ model.setTimeRemaining(timeRemaining);
+ }
+ Navigation.findNavController(requireView()).navigate(RegistrationLockFragmentDirections.actionAccountLocked());
}
@Override
diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RegistrationLockFragment.java b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RegistrationLockFragment.java
index 3b79b78429..b0085fd37d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RegistrationLockFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/RegistrationLockFragment.java
@@ -192,7 +192,7 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
if (triesRemaining == 0) {
Log.w(TAG, "Account locked. User out of attempts on KBS.");
- lockAccount(timeRemaining);
+ onAccountLocked();
return;
}
@@ -226,10 +226,12 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
}
@Override
- public void onKbsAccountLocked(long timeRemaining) {
- getModel().setTimeRemaining(timeRemaining);
+ public void onKbsAccountLocked(@Nullable Long timeRemaining) {
+ if (timeRemaining != null) {
+ model.setTimeRemaining(timeRemaining);
+ }
- lockAccount(timeRemaining);
+ onAccountLocked();
}
@Override
@@ -254,10 +256,8 @@ public final class RegistrationLockFragment extends BaseRegistrationFragment {
return (int) TimeUnit.MILLISECONDS.toDays(timeRemainingMs) + 1;
}
- private void lockAccount(long timeRemaining) {
- RegistrationLockFragmentDirections.ActionAccountLocked action = RegistrationLockFragmentDirections.actionAccountLocked(timeRemaining);
-
- Navigation.findNavController(requireView()).navigate(action);
+ private void onAccountLocked() {
+ Navigation.findNavController(requireView()).navigate(RegistrationLockFragmentDirections.actionAccountLocked());
}
private void updateKeyboard(@NonNull PinKeyboardType keyboard) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/service/CodeVerificationRequest.java b/app/src/main/java/org/thoughtcrime/securesms/registration/service/CodeVerificationRequest.java
index a2968f2925..9ce60e3769 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/registration/service/CodeVerificationRequest.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/registration/service/CodeVerificationRequest.java
@@ -35,6 +35,7 @@ import org.whispersystems.libsignal.util.KeyHelper;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.KeyBackupServicePinException;
+import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
import org.whispersystems.signalservice.api.RegistrationLockData;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.kbs.HashedPin;
@@ -94,6 +95,9 @@ public final class CodeVerificationRequest {
kbsToken = kbsTokenResponse;
verifyAccount(context, credentials, code, pin, kbsTokenResponse, basicStorageCredentials, fcmToken);
return Result.SUCCESS;
+ } catch (KeyBackupSystemNoDataException e) {
+ Log.w(TAG, "No data found on KBS");
+ return Result.KBS_ACCOUNT_LOCKED;
} catch (KeyBackupSystemWrongPinException e) {
kbsToken = e.getTokenResponse();
return Result.KBS_WRONG_PIN;
@@ -156,7 +160,7 @@ public final class CodeVerificationRequest {
break;
case KBS_ACCOUNT_LOCKED:
Log.w(TAG, "KBS Account is locked");
- callback.onKbsAccountLocked(lockedException.getTimeRemaining());
+ callback.onKbsAccountLocked(lockedException != null ? lockedException.getTimeRemaining() : null);
break;
}
}
@@ -184,7 +188,7 @@ public final class CodeVerificationRequest {
@Nullable TokenResponse kbsTokenResponse,
@Nullable String kbsStorageCredentials,
@Nullable String fcmToken)
- throws IOException, KeyBackupSystemWrongPinException
+ throws IOException, KeyBackupSystemWrongPinException, KeyBackupSystemNoDataException
{
boolean isV2KbsPin = kbsTokenResponse != null;
int registrationId = KeyHelper.generateRegistrationId(false);
@@ -284,7 +288,7 @@ public final class CodeVerificationRequest {
private static @Nullable RegistrationLockData restoreMasterKey(@Nullable String pin,
@Nullable String basicStorageCredentials,
@NonNull TokenResponse tokenResponse)
- throws IOException, KeyBackupSystemWrongPinException
+ throws IOException, KeyBackupSystemWrongPinException, KeyBackupSystemNoDataException
{
if (pin == null) return null;
@@ -304,7 +308,7 @@ public final class CodeVerificationRequest {
if (kbsData != null) {
Log.i(TAG, "Found registration lock token on KBS.");
} else {
- Log.i(TAG, "No KBS data found.");
+ throw new AssertionError("Null not expected");
}
return kbsData;
} catch (UnauthenticatedResponseException e) {
@@ -340,11 +344,11 @@ public final class CodeVerificationRequest {
void onIncorrectKbsRegistrationLockPin(@NonNull TokenResponse kbsTokenResponse);
/**
- * V2 (KBS) pin is set, but there is no data on KBS
+ * V2 (KBS) pin is set, but there is no data on KBS.
*
- * @param timeRemaining Time until pin expires and number can be reused.
+ * @param timeRemaining Non-null if known.
*/
- void onKbsAccountLocked(long timeRemaining);
+ void onKbsAccountLocked(@Nullable Long timeRemaining);
void onRateLimited();
diff --git a/app/src/main/res/navigation/registration.xml b/app/src/main/res/navigation/registration.xml
index c21d3d6465..01d3343c2b 100644
--- a/app/src/main/res/navigation/registration.xml
+++ b/app/src/main/res/navigation/registration.xml
@@ -157,12 +157,7 @@
android:id="@+id/accountLockedFragment"
android:name="org.thoughtcrime.securesms.registration.fragments.AccountLockedFragment"
android:label="fragment_account_locked"
- tools:layout="@layout/account_locked_fragment">
-
-
-
+ tools:layout="@layout/account_locked_fragment"/>