From 138dae0484a50228fd403330ce3cc86ecddb3b6b Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Thu, 17 Apr 2025 17:39:33 -0300 Subject: [PATCH] Align pin reminder skip behavior with iOS. --- .../securesms/keyvalue/PinValues.java | 42 +++++++++++++++---- .../securesms/lock/SignalPinReminders.java | 19 +++++++++ .../securesms/logsubmit/LogSectionPin.java | 1 + .../securesms/megaphone/Megaphones.java | 7 ++-- .../megaphone/SignalPinReminderSchedule.java | 6 +-- app/src/main/res/values/strings.xml | 6 +++ 6 files changed, 68 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PinValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PinValues.java index 8a140cb773..ecff59e28d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PinValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/PinValues.java @@ -19,6 +19,7 @@ public final class PinValues extends SignalStoreValues { private static final String TAG = Log.tag(PinValues.class); private static final String LAST_SUCCESSFUL_ENTRY = "pin.last_successful_entry"; + private static final String LAST_REMINDER_TIME = "pin.last_reminder_time"; private static final String NEXT_INTERVAL = "pin.interval_index"; private static final String KEYBOARD_TYPE = "kbs.keyboard_type"; public static final String PIN_REMINDERS_ENABLED = "pin.pin_reminders_enabled"; @@ -40,9 +41,12 @@ public final class PinValues extends SignalStoreValues { long nextInterval = SignalPinReminders.getNextInterval(getCurrentInterval()); Log.i(TAG, "onEntrySuccess() nextInterval: " + nextInterval); + long now = System.currentTimeMillis(); + getStore().beginWrite() - .putLong(LAST_SUCCESSFUL_ENTRY, System.currentTimeMillis()) + .putLong(LAST_SUCCESSFUL_ENTRY, now) .putLong(NEXT_INTERVAL, nextInterval) + .putLong(LAST_REMINDER_TIME, now) .apply(); SignalStore.svr().setPinIfNotPresent(pin); @@ -52,28 +56,48 @@ public final class PinValues extends SignalStoreValues { long nextInterval = SignalPinReminders.getPreviousInterval(getCurrentInterval()); Log.i(TAG, "onEntrySuccessWithWrongGuess() nextInterval: " + nextInterval); + long now = System.currentTimeMillis(); + getStore().beginWrite() - .putLong(LAST_SUCCESSFUL_ENTRY, System.currentTimeMillis()) + .putLong(LAST_SUCCESSFUL_ENTRY, now) .putLong(NEXT_INTERVAL, nextInterval) + .putLong(LAST_REMINDER_TIME, now) .apply(); SignalStore.svr().setPinIfNotPresent(pin); } - public void onEntrySkipWithWrongGuess() { - long nextInterval = SignalPinReminders.getPreviousInterval(getCurrentInterval()); - Log.i(TAG, "onEntrySkipWithWrongGuess() nextInterval: " + nextInterval); + /** + * Updates LAST_REMINDER_TIME and in the case of a failed guess, ratches + * back the interval until next reminder. + */ + public void onEntrySkip(boolean includedFailure) { + long nextInterval; - putLong(NEXT_INTERVAL, nextInterval); + if (includedFailure) { + nextInterval = SignalPinReminders.getPreviousInterval(getCurrentInterval()); + } else { + nextInterval = getCurrentInterval(); + } + + Log.i(TAG, "onEntrySkip(includedFailure: " + includedFailure +") nextInterval: " + nextInterval); + + getStore().beginWrite() + .putLong(NEXT_INTERVAL, nextInterval) + .putLong(LAST_REMINDER_TIME, System.currentTimeMillis()) + .apply(); } public void resetPinReminders() { long nextInterval = SignalPinReminders.INITIAL_INTERVAL; Log.i(TAG, "resetPinReminders() nextInterval: " + nextInterval, new Throwable()); + long now = System.currentTimeMillis(); + getStore().beginWrite() .putLong(NEXT_INTERVAL, nextInterval) - .putLong(LAST_SUCCESSFUL_ENTRY, System.currentTimeMillis()) + .putLong(LAST_SUCCESSFUL_ENTRY, now) + .putLong(LAST_REMINDER_TIME, now) .apply(); } @@ -85,6 +109,10 @@ public final class PinValues extends SignalStoreValues { return getLong(LAST_SUCCESSFUL_ENTRY, TextSecurePreferences.getRegistrationLockLastReminderTime(AppDependencies.getApplication())); } + public long getLastReminderTime() { + return getLong(LAST_REMINDER_TIME, getLastSuccessfulEntryTime()); + } + public void setKeyboardType(@NonNull PinKeyboardType keyboardType) { putString(KEYBOARD_TYPE, keyboardType.getCode()); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/lock/SignalPinReminders.java b/app/src/main/java/org/thoughtcrime/securesms/lock/SignalPinReminders.java index c2f7fa3fd4..652d6fc837 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/lock/SignalPinReminders.java +++ b/app/src/main/java/org/thoughtcrime/securesms/lock/SignalPinReminders.java @@ -40,6 +40,14 @@ public class SignalPinReminders { put(FOUR_WEEKS, R.string.SignalPinReminders_well_remind_you_again_in_a_month); }}; + private static final Map SKIP_STRINGS = new HashMap() {{ + put(ONE_DAY, R.string.SignalPinReminders__well_remind_you_again_tomorrow); + put(THREE_DAYS, R.string.SignalPinReminders__well_remind_you_again_in_a_few_days); + put(ONE_WEEK, R.string.SignalPinReminders__well_remind_you_again_in_a_week); + put(TWO_WEEKS, R.string.SignalPinReminders__well_remind_you_again_in_a_couple_weeks); + put(FOUR_WEEKS, R.string.SignalPinReminders__well_remind_you_again_in_a_month); + }}; + public static final long INITIAL_INTERVAL = INTERVALS.first(); public static long getNextInterval(long currentInterval) { @@ -62,4 +70,15 @@ public class SignalPinReminders { return R.string.SignalPinReminders_well_remind_you_again_later; } } + + public static @StringRes int getSkipReminderString(long interval) { + Integer stringRes = SKIP_STRINGS.get(interval); + + if (stringRes != null) { + return stringRes; + } else { + Log.w(TAG, "Couldn't find a string for interval " + interval); + return R.string.SignalPinReminders__well_remind_you_again_later; + } + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionPin.java b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionPin.java index c2393acbee..1e297f94cd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionPin.java +++ b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionPin.java @@ -16,6 +16,7 @@ public class LogSectionPin implements LogSection { @Override public @NonNull CharSequence getContent(@NonNull Context context) { return new StringBuilder().append("Last Successful Reminder Entry: ").append(SignalStore.pin().getLastSuccessfulEntryTime()).append("\n") + .append("Last Reminder Time: ").append(SignalStore.pin().getLastReminderTime()).append("\n") .append("Next Reminder Interval: ").append(SignalStore.pin().getCurrentInterval()).append("\n") .append("Reglock: ").append(SignalStore.svr().isRegistrationLockEnabled()).append("\n") .append("Signal PIN: ").append(SignalStore.svr().hasPin()).append("\n") diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java index a886325cb0..b99bfbbb21 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/Megaphones.java @@ -236,9 +236,10 @@ public final class Megaphones { @Override public void onReminderDismissed(boolean includedFailure) { Log.i(TAG, "[PinReminder] onReminderDismissed(" + includedFailure + ")"); - if (includedFailure) { - SignalStore.pin().onEntrySkipWithWrongGuess(); - } + + SignalStore.pin().onEntrySkip(includedFailure); + controller.onMegaphoneSnooze(Event.PIN_REMINDER); + controller.onMegaphoneToastRequested(controller.getMegaphoneActivity().getString(SignalPinReminders.getSkipReminderString(SignalStore.pin().getCurrentInterval()))); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/SignalPinReminderSchedule.java b/app/src/main/java/org/thoughtcrime/securesms/megaphone/SignalPinReminderSchedule.java index e36c2a9e7c..b0e1d95cae 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/SignalPinReminderSchedule.java +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/SignalPinReminderSchedule.java @@ -22,9 +22,9 @@ final class SignalPinReminderSchedule implements MegaphoneSchedule { return false; } - long lastSuccessTime = SignalStore.pin().getLastSuccessfulEntryTime(); - long interval = SignalStore.pin().getCurrentInterval(); + long lastReminderTime = SignalStore.pin().getLastReminderTime(); + long interval = SignalStore.pin().getCurrentInterval(); - return currentTime - lastSuccessTime >= interval; + return currentTime - lastReminderTime >= interval; } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b9117ebf14..2650bd42c0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2769,6 +2769,12 @@ PIN verified successfully. We\'ll remind you again in a week. PIN verified successfully. We\'ll remind you again in a couple weeks. PIN verified successfully. We\'ll remind you again in a month. + We\'ll remind you again later. + We\'ll remind you again tomorrow. + We\'ll remind you again in a few days. + We\'ll remind you again in a week. + We\'ll remind you again in a couple weeks. + We\'ll remind you again in a month. Image