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 b3db0acfb2..20f32853cd 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
@@ -1,6 +1,8 @@
package org.thoughtcrime.securesms.registration.fragments;
+import android.animation.Animator;
import android.os.Bundle;
+import android.telephony.PhoneStateListener;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -36,7 +38,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-public final class EnterCodeFragment extends BaseRegistrationFragment {
+public final class EnterCodeFragment extends BaseRegistrationFragment
+ implements SignalStrengthPhoneStateListener.Callback
+{
private static final String TAG = Log.tag(EnterCodeFragment.class);
@@ -47,8 +51,11 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
private CallMeCountDownView callMeCountDown;
private View wrongNumber;
private View noCodeReceivedHelp;
+ private View serviceWarning;
private boolean autoCompleting;
+ private PhoneStateListener signalStrengthListener;
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_registration_enter_code, container, false);
@@ -67,6 +74,9 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
callMeCountDown = view.findViewById(R.id.call_me_count_down);
wrongNumber = view.findViewById(R.id.wrong_number);
noCodeReceivedHelp = view.findViewById(R.id.no_code);
+ serviceWarning = view.findViewById(R.id.cell_service_warning);
+
+ signalStrengthListener = new SignalStrengthPhoneStateListener(this, this);
connectKeyboard(verificationCodeView, keyboard);
@@ -319,4 +329,40 @@ public final class EnterCodeFragment extends BaseRegistrationFragment {
getString(R.string.RegistrationActivity_code_support_subject),
body);
}
+
+ @Override
+ public void onNoCellSignalPresent() {
+ if (serviceWarning.getVisibility() == View.VISIBLE) {
+ return;
+ }
+ serviceWarning.setVisibility(View.VISIBLE);
+ serviceWarning.animate()
+ .alpha(1)
+ .setListener(null)
+ .start();
+
+ scrollView.postDelayed(() -> {
+ if (serviceWarning.getVisibility() == View.VISIBLE) {
+ scrollView.smoothScrollTo(0, serviceWarning.getBottom());
+ }
+ }, 1000);
+ }
+
+ @Override
+ public void onCellSignalPresent() {
+ if (serviceWarning.getVisibility() != View.VISIBLE) {
+ return;
+ }
+ serviceWarning.animate()
+ .alpha(0)
+ .setListener(new Animator.AnimatorListener() {
+ @Override public void onAnimationEnd(Animator animation) {
+ serviceWarning.setVisibility(View.GONE);
+ }
+ @Override public void onAnimationStart(Animator animation) {}
+ @Override public void onAnimationCancel(Animator animation) {}
+ @Override public void onAnimationRepeat(Animator animation) {}
+ })
+ .start();
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/SignalStrengthPhoneStateListener.java b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/SignalStrengthPhoneStateListener.java
new file mode 100644
index 0000000000..fded5f0aaf
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/registration/fragments/SignalStrengthPhoneStateListener.java
@@ -0,0 +1,73 @@
+package org.thoughtcrime.securesms.registration.fragments;
+
+import android.content.Context;
+import android.os.Build;
+import android.telephony.PhoneStateListener;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import org.signal.core.util.logging.Log;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
+import org.thoughtcrime.securesms.util.Debouncer;
+
+final class SignalStrengthPhoneStateListener extends PhoneStateListener
+ implements DefaultLifecycleObserver
+{
+ private static final String TAG = Log.tag(SignalStrengthPhoneStateListener.class);
+
+ private final Callback callback;
+ private final Debouncer debouncer = new Debouncer(1000);
+
+ SignalStrengthPhoneStateListener(@NonNull LifecycleOwner lifecycleOwner, @NonNull Callback callback) {
+ this.callback = callback;
+
+ lifecycleOwner.getLifecycle().addObserver(this);
+ }
+
+ @Override
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ if (signalStrength == null) return;
+
+ if (isLowLevel(signalStrength)) {
+ Log.w(TAG, "No cell signal detected");
+ debouncer.publish(callback::onNoCellSignalPresent);
+ } else {
+ Log.i(TAG, "Cell signal detected");
+ debouncer.clear();
+ callback.onCellSignalPresent();
+ }
+ }
+
+ private boolean isLowLevel(@NonNull SignalStrength signalStrength) {
+ if (Build.VERSION.SDK_INT >= 23) {
+ return signalStrength.getLevel() == 0;
+ } else {
+ //noinspection deprecation: False lint warning, deprecated by 29, but this else block is for < 23
+ return signalStrength.getGsmSignalStrength() == 0;
+ }
+ }
+
+ interface Callback {
+ void onNoCellSignalPresent();
+
+ void onCellSignalPresent();
+ }
+
+ @Override
+ public void onResume(@NonNull LifecycleOwner owner) {
+ TelephonyManager telephonyManager = (TelephonyManager) ApplicationDependencies.getApplication().getSystemService(Context.TELEPHONY_SERVICE);
+ telephonyManager.listen(this, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
+ Log.i(TAG, "Listening to cell phone signal strength changes");
+ }
+
+ @Override
+ public void onPause(@NonNull LifecycleOwner owner) {
+ TelephonyManager telephonyManager = (TelephonyManager) ApplicationDependencies.getApplication().getSystemService(Context.TELEPHONY_SERVICE);
+ telephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
+ Log.i(TAG, "Stopped listening to cell phone signal strength changes");
+ }
+}
diff --git a/app/src/main/res/drawable/ic_error_outline_14_ultramarine.xml b/app/src/main/res/drawable/ic_error_outline_14_ultramarine.xml
new file mode 100644
index 0000000000..66049ea07b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_error_outline_14_ultramarine.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/registration_no_cell_service_warning_border.xml b/app/src/main/res/drawable/registration_no_cell_service_warning_border.xml
new file mode 100644
index 0000000000..f447a27c6b
--- /dev/null
+++ b/app/src/main/res/drawable/registration_no_cell_service_warning_border.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_registration_enter_code.xml b/app/src/main/res/layout/fragment_registration_enter_code.xml
index 3e86fbc525..81b24681ab 100644
--- a/app/src/main/res/layout/fragment_registration_enter_code.xml
+++ b/app/src/main/res/layout/fragment_registration_enter_code.xml
@@ -88,6 +88,48 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/verify_header" />
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 453d624599..0b60a4c122 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1509,6 +1509,7 @@
Enter your phone number to get started
You will receive a verification code. Carrier rates may apply.
Enter the code we sent to %s
+ Make sure your phone has a cellular signal to receive your SMS or call
Phone number
Country code