Add lock screen help dialog.

This commit is contained in:
Greyson Parrelli
2024-06-25 12:48:01 -04:00
committed by Cody Henthorne
parent 058c523329
commit 47cd1b568f
4 changed files with 59 additions and 2 deletions

View File

@@ -661,7 +661,7 @@
<activity android:name=".PassphrasePromptActivity"
android:launchMode="singleTask"
android:theme="@style/TextSecure.LightIntroTheme"
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:exported="false"/>

View File

@@ -44,10 +44,13 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.biometric.BiometricManager;
import androidx.biometric.BiometricPrompt;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
@@ -55,6 +58,7 @@ import org.thoughtcrime.securesms.components.AnimatingToggle;
import org.thoughtcrime.securesms.crypto.InvalidPassphraseException;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogActivity;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.DynamicIntroTheme;
@@ -74,7 +78,8 @@ public class PassphrasePromptActivity extends PassphraseActivity {
private static final String TAG = Log.tag(PassphrasePromptActivity.class);
private static final short AUTHENTICATE_REQUEST_CODE = 1007;
private static final String BUNDLE_ALREADY_SHOWN = "bundle_already_shown";
public static final String FROM_FOREGROUND = "from_foreground";
public static final String FROM_FOREGROUND = "from_foreground";
private static final int HELP_COUNT_THRESHOLD = 3;
private DynamicIntroTheme dynamicTheme = new DynamicIntroTheme();
private DynamicLanguage dynamicLanguage = new DynamicLanguage();
@@ -188,6 +193,7 @@ public class PassphrasePromptActivity extends PassphraseActivity {
} else {
Log.w(TAG, "Authentication failed");
hadFailure = true;
incrementAttemptCountAndShowHelpIfNecessary();
}
}
@@ -207,6 +213,7 @@ public class PassphrasePromptActivity extends PassphraseActivity {
passphraseText.setText("");
passphraseText.setError(
getString(R.string.PassphrasePromptActivity_invalid_passphrase_exclamation));
incrementAttemptCountAndShowHelpIfNecessary();
}
}
@@ -216,6 +223,7 @@ public class PassphrasePromptActivity extends PassphraseActivity {
MasterSecret masterSecret = MasterSecretUtil.getMasterSecret(this, MasterSecretUtil.UNENCRYPTED_PASSPHRASE);
setMasterSecret(masterSecret);
SignalStore.misc().setLockScreenAttemptCount(0);
} catch (InvalidPassphraseException e) {
throw new AssertionError(e);
}
@@ -272,6 +280,10 @@ public class PassphrasePromptActivity extends PassphraseActivity {
fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.core_ultramarine), PorterDuff.Mode.SRC_IN);
lockScreenButton.setOnClickListener(v -> resumeScreenLock(true));
if (SignalStore.misc().getLockScreenAttemptCount() > HELP_COUNT_THRESHOLD) {
showHelpDialogAndResetAttemptCount(null);
}
}
private void setLockTypeVisibility() {
@@ -288,6 +300,10 @@ public class PassphrasePromptActivity extends PassphraseActivity {
}
private void resumeScreenLock(boolean force) {
if (incrementAttemptCountAndShowHelpIfNecessary(() -> resumeScreenLock(force))) {
return;
}
if (!biometricAuth.authenticate(getApplicationContext(), force, this::showConfirmDeviceCredentialIntent)) {
handleAuthenticated();
}
@@ -312,6 +328,33 @@ public class PassphrasePromptActivity extends PassphraseActivity {
return Unit.INSTANCE;
}
private boolean incrementAttemptCountAndShowHelpIfNecessary() {
return incrementAttemptCountAndShowHelpIfNecessary(null);
}
private boolean incrementAttemptCountAndShowHelpIfNecessary(Runnable onDismissed) {
SignalStore.misc().incrementLockScreenAttemptCount();
if (SignalStore.misc().getLockScreenAttemptCount() > HELP_COUNT_THRESHOLD) {
showHelpDialogAndResetAttemptCount(onDismissed);
return true;
}
return false;
}
private void showHelpDialogAndResetAttemptCount(@Nullable Runnable onDismissed) {
new MaterialAlertDialogBuilder(this)
.setMessage(R.string.PassphrasePromptActivity_help_prompt_body)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
SignalStore.misc().setLockScreenAttemptCount(0);
if (onDismissed != null) {
onDismissed.run();
}
})
.show();
}
private class PassphraseActionListener implements TextView.OnEditorActionListener {
@Override
public boolean onEditorAction(TextView exampleView, int actionId, KeyEvent keyEvent) {
@@ -366,6 +409,8 @@ public class PassphrasePromptActivity extends PassphraseActivity {
Log.w(TAG, "Authentication error: " + errorCode);
hadFailure = true;
incrementAttemptCountAndShowHelpIfNecessary();
if (errorCode != BiometricPrompt.ERROR_CANCELED && errorCode != BiometricPrompt.ERROR_USER_CANCELED) {
onAuthenticationFailed();
}

View File

@@ -36,6 +36,7 @@ class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalSto
private const val LINKED_DEVICE_LAST_ACTIVE_CHECK_TIME = "misc.linked_device.last_active_check_time"
private const val LEAST_ACTIVE_LINKED_DEVICE = "misc.linked_device.least_active"
private const val NEXT_DATABASE_ANALYSIS_TIME = "misc.next_database_analysis_time"
private const val LOCK_SCREEN_ATTEMPT_COUNT = "misc.lock_screen_attempt_count"
}
public override fun onFirstEverAppLaunch() {
@@ -248,4 +249,13 @@ class MiscellaneousValues internal constructor(store: KeyValueStore) : SignalSto
* When the next scheduled database analysis is.
*/
var nextDatabaseAnalysisTime: Long by longValue(NEXT_DATABASE_ANALYSIS_TIME, 0)
/**
* How many times the lock screen has been seen and _not_ unlocked. Used to determine if the user is confused by how to bypass the lock screen.
*/
var lockScreenAttemptCount: Int by integerValue(LOCK_SCREEN_ATTEMPT_COUNT, 0)
fun incrementLockScreenAttemptCount() {
lockScreenAttemptCount++
}
}

View File

@@ -7127,6 +7127,8 @@
<string name="RemoteBackupsSettingsFragment__monthly">Monthly</string>
<!-- Title for frequency option DAILY for backup frequency -->
<string name="RemoteBackupsSettingsFragment__manually_back_up">Manually back up</string>
<!-- The body of an alert dialog shown when we detect the user may be confused by the lock screen -->
<string name="PassphrasePromptActivity_help_prompt_body">Please enter your device pin, password or pattern.</string>
<!-- EOF -->
</resources>