> chunks = new ArrayList<>(list.size() / chunkSize);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java
index cf438a23aa..140ccdcbad 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java
@@ -38,6 +38,7 @@ import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
+import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
@@ -290,4 +291,9 @@ public class ViewUtil {
}
return result;
}
+
+ public static void hideKeyboard(@NonNull Context context, @NonNull View view) {
+ InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
+ inputManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
+ }
}
diff --git a/app/src/main/res/layout/pin_restore_activity.xml b/app/src/main/res/layout/pin_restore_activity.xml
new file mode 100644
index 0000000000..ee75bfdb0f
--- /dev/null
+++ b/app/src/main/res/layout/pin_restore_activity.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/pin_restore_entry_fragment.xml b/app/src/main/res/layout/pin_restore_entry_fragment.xml
new file mode 100644
index 0000000000..a32ce5c663
--- /dev/null
+++ b/app/src/main/res/layout/pin_restore_entry_fragment.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/pin_restore_locked_fragment.xml b/app/src/main/res/layout/pin_restore_locked_fragment.xml
new file mode 100644
index 0000000000..bb2171d3c8
--- /dev/null
+++ b/app/src/main/res/layout/pin_restore_locked_fragment.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/pin_restore.xml b/app/src/main/res/navigation/pin_restore.xml
new file mode 100644
index 0000000000..d6b6963b95
--- /dev/null
+++ b/app/src/main/res/navigation/pin_restore.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7c0c7d7afd..6264e92aa8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -132,6 +132,7 @@
No web browser found.
+ No email app found.
A cellular call is already in progress.
Start video call?
Start voice call?
@@ -788,6 +789,32 @@
The version of Google Play Services you have installed is not functioning correctly. Please reinstall Google Play Services and try again.
+
+ Incorrect PIN
+ Skip PIN entry?
+ Need help?
+ Your PIN is a %1$d+ digit code you created that can be numeric or alphanumeric.\n\nIf you can’t remember your PIN, you can create a new one. You can register and use your account but you’ll lose some saved settings like your profile information.
+ If you can’t remember your PIN, you can create a new one. You can register and use your account but you’ll lose some saved settings like your profile information.
+ Create New PIN
+ Contact Support
+ Cancel
+ Skip
+
+ - You have %1$d attempt remaining. If you run out of attempts, you can create a new PIN. You can register and use your account but you’ll lose some saved settings like your profile information.
+ - You have %1$d attempts remaining. If you run out of attempts, you can create a new PIN. You can register and use your account but you’ll lose some saved settings like your profile information.
+
+ support@signal.org
+ Signal Registration - Need Help with PIN for Android
+ Subject: Signal Registration - Need Help with PIN for Android\nDevice info: %1$s\nAndroid version: %2$s\nSignal version: %3$s\nLocale: %4$s
+ Enter alphanumeric PIN
+ Enter numeric PIN
+
+
+ Create your PIN
+ You\'ve run out of PIN guesses, but you can still access your Signal account by creating a new PIN. For your privacy and security your account will be restored without any saved profile information or settings.
+ Create new PIN
+ https://support.signal.org/hc/articles/360007059792
+
Rate this app
If you enjoy using this app, please take a moment to help us by rating it.
diff --git a/app/src/test/java/org/thoughtcrime/securesms/megaphone/PinsForAllScheduleTest.java b/app/src/test/java/org/thoughtcrime/securesms/megaphone/PinsForAllScheduleTest.java
index f37631b40e..1103abb03d 100644
--- a/app/src/test/java/org/thoughtcrime/securesms/megaphone/PinsForAllScheduleTest.java
+++ b/app/src/test/java/org/thoughtcrime/securesms/megaphone/PinsForAllScheduleTest.java
@@ -102,7 +102,7 @@ public class PinsForAllScheduleTest {
public void whenUserIsANewInstallAndFlagIsDisabled_whenIShouldDisplay_thenIExpectFalse() {
// GIVEN
when(registrationValues.pinWasRequiredAtRegistration()).thenReturn(true);
- when(kbsValues.isV2RegistrationLockEnabled()).thenReturn(true);
+ when(kbsValues.hasPin()).thenReturn(true);
when(FeatureFlags.pinsForAll()).thenReturn(false);
// WHEN
@@ -116,7 +116,7 @@ public class PinsForAllScheduleTest {
public void whenUserIsANewInstallAndFlagIsEnabled_whenIShouldDisplay_thenIExpectFalse() {
// GIVEN
when(registrationValues.pinWasRequiredAtRegistration()).thenReturn(true);
- when(kbsValues.isV2RegistrationLockEnabled()).thenReturn(true);
+ when(kbsValues.hasPin()).thenReturn(true);
when(FeatureFlags.pinsForAll()).thenReturn(true);
// WHEN
diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/KeyBackupService.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/KeyBackupService.java
index 775c4ae560..795389e5dc 100644
--- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/KeyBackupService.java
+++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/KeyBackupService.java
@@ -71,12 +71,19 @@ public final class KeyBackupService {
/**
* Only call before registration, to see how many tries are left.
*
- * Pass the token to the newRegistrationSession.
+ * Pass the token to {@link #newRegistrationSession(String, TokenResponse)}.
*/
public TokenResponse getToken(String authAuthorization) throws IOException {
return pushServiceSocket.getKeyBackupServiceToken(authAuthorization, enclaveName);
}
+ /**
+ * Retrieve the authorization token to be used with other requests.
+ */
+ public String getAuthorization() throws IOException {
+ return pushServiceSocket.getKeyBackupServiceAuthorization();
+ }
+
/**
* Use this during registration, good for one try, on subsequent attempts, pass the token from the previous attempt.
*
diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java
index 4a9799764c..24bf6d2ba5 100644
--- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java
+++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java
@@ -62,6 +62,7 @@ import org.whispersystems.signalservice.internal.push.ProfileAvatarData;
import org.whispersystems.signalservice.internal.push.PushServiceSocket;
import org.whispersystems.signalservice.internal.push.RemoteAttestationUtil;
import org.whispersystems.signalservice.internal.push.RemoteConfigResponse;
+import org.whispersystems.signalservice.internal.push.VerifyAccountResponse;
import org.whispersystems.signalservice.internal.push.http.ProfileCipherOutputStreamFactory;
import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord;
import org.whispersystems.signalservice.internal.storage.protos.ReadOperation;
@@ -239,10 +240,10 @@ public class SignalServiceAccountManager {
* @return The UUID of the user that was registered.
* @throws IOException
*/
- public UUID verifyAccountWithCode(String verificationCode, String signalingKey, int signalProtocolRegistrationId, boolean fetchesMessages,
- String pin, String registrationLock,
- byte[] unidentifiedAccessKey, boolean unrestrictedUnidentifiedAccess,
- SignalServiceProfile.Capabilities capabilities)
+ public VerifyAccountResponse verifyAccountWithCode(String verificationCode, String signalingKey, int signalProtocolRegistrationId, boolean fetchesMessages,
+ String pin, String registrationLock,
+ byte[] unidentifiedAccessKey, boolean unrestrictedUnidentifiedAccess,
+ SignalServiceProfile.Capabilities capabilities)
throws IOException
{
return this.pushServiceSocket.verifyAccountCode(verificationCode, signalingKey,
diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java
index 345ebc9527..f3ab9e4bc4 100644
--- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java
+++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/PushServiceSocket.java
@@ -271,23 +271,17 @@ public class PushServiceSocket {
}
}
- public UUID verifyAccountCode(String verificationCode, String signalingKey, int registrationId, boolean fetchesMessages,
+ public VerifyAccountResponse verifyAccountCode(String verificationCode, String signalingKey, int registrationId, boolean fetchesMessages,
String pin, String registrationLock,
byte[] unidentifiedAccessKey, boolean unrestrictedUnidentifiedAccess,
SignalServiceProfile.Capabilities capabilities)
throws IOException
{
- AccountAttributes signalingKeyEntity = new AccountAttributes(signalingKey, registrationId, fetchesMessages, pin, registrationLock, unidentifiedAccessKey, unrestrictedUnidentifiedAccess, capabilities);
- String requestBody = JsonUtil.toJson(signalingKeyEntity);
- String responseBody = makeServiceRequest(String.format(VERIFY_ACCOUNT_CODE_PATH, verificationCode), "PUT", requestBody);
- VerifyAccountResponse response = JsonUtil.fromJson(responseBody, VerifyAccountResponse.class);
- Optional uuid = UuidUtil.parse(response.getUuid());
+ AccountAttributes signalingKeyEntity = new AccountAttributes(signalingKey, registrationId, fetchesMessages, pin, registrationLock, unidentifiedAccessKey, unrestrictedUnidentifiedAccess, capabilities);
+ String requestBody = JsonUtil.toJson(signalingKeyEntity);
+ String responseBody = makeServiceRequest(String.format(VERIFY_ACCOUNT_CODE_PATH, verificationCode), "PUT", requestBody);
- if (uuid.isPresent()) {
- return uuid.get();
- } else {
- throw new IOException("Invalid UUID!");
- }
+ return JsonUtil.fromJson(responseBody, VerifyAccountResponse.class);
}
public void setAccountAttributes(String signalingKey, int registrationId, boolean fetchesMessages,
diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/VerifyAccountResponse.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/VerifyAccountResponse.java
index b5cdde4b5f..67867b2b7b 100644
--- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/VerifyAccountResponse.java
+++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/VerifyAccountResponse.java
@@ -6,7 +6,14 @@ public class VerifyAccountResponse {
@JsonProperty
private String uuid;
+ @JsonProperty
+ private boolean storageCapable;
+
public String getUuid() {
return uuid;
}
+
+ public boolean isStorageCapable() {
+ return storageCapable;
+ }
}