Skip to content

Commit

Permalink
Handle active notifications on passphrase lock timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
valldrac committed Nov 16, 2023
1 parent bb66445 commit 7fba50a
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.core.content.ContextCompat;
import androidx.multidex.MultiDexApplication;

import com.google.android.gms.security.ProviderInstaller;
Expand Down Expand Up @@ -84,6 +85,7 @@
import org.thoughtcrime.securesms.mms.SignalGlideComponents;
import org.thoughtcrime.securesms.mms.SignalGlideModule;
import org.thoughtcrime.securesms.net.NetworkManager;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.ratelimit.RateLimitUtil;
import org.thoughtcrime.securesms.recipients.Recipient;
Expand Down Expand Up @@ -310,7 +312,7 @@ public void onUnlock() {
}

@MainThread
public void onLock() {
public void onLock(boolean keyExpired) {
Log.i(TAG, "onLock()");

stopService(new Intent(this, WebRtcCallService.class));
Expand All @@ -319,6 +321,16 @@ public void onLock() {
finalizeMessageRetrieval();
unregisterKeyEventReceiver();

MessageNotifier messageNotifier = ApplicationDependencies.getMessageNotifier();
messageNotifier.cancelDelayedNotifications();
boolean hadActiveNotifications = messageNotifier.clearNotifications(this);

if (hadActiveNotifications && keyExpired && SignalStore.account().isPushAvailable() &&
TextSecurePreferences.isPassphraseLockNotificationsEnabled(this) ) {
Log.d(TAG, "Replacing active notifications with may-have-messages notification");
FcmFetchManager.postMayHaveMessagesNotification(this);
}

ThreadUtil.runOnMainDelayed(() -> {
ApplicationDependencies.getJobManager().shutdown(TimeUnit.SECONDS.toMillis(10));
KeyCachingService.clearMasterSecret();
Expand Down Expand Up @@ -628,15 +640,15 @@ public void e(@NonNull String tag, @NonNull String message, @Nullable Throwable
private final BroadcastReceiver keyEventReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
onLock();
boolean keyExpired = intent.getBooleanExtra(KeyCachingService.EXTRA_KEY_EXPIRED, false);
onLock(keyExpired);
}
};

private void registerKeyEventReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(KeyCachingService.CLEAR_KEY_EVENT);

registerReceiver(keyEventReceiver, filter, KeyCachingService.KEY_PERMISSION, null);
ContextCompat.registerReceiver(this, keyEventReceiver, filter, KeyCachingService.KEY_PERMISSION, null, ContextCompat.RECEIVER_NOT_EXPORTED);
}

private void unregisterKeyEventReceiver() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public interface MessageNotifier {
void updateNotification(@NonNull Context context, @NonNull ConversationId conversationId, @NonNull BubbleUtil.BubbleState defaultBubbleState);
void updateNotification(@NonNull Context context, @NonNull ConversationId conversationId, boolean signal);
void updateNotification(@NonNull Context context, @Nullable ConversationId conversationId, boolean signal, int reminderCount, @NonNull BubbleUtil.BubbleState defaultBubbleState);
void clearNotifications(@NonNull Context context);
boolean clearNotifications(@NonNull Context context);
void clearReminder(@NonNull Context context);
void addStickyThread(@NonNull ConversationId conversationId, long earliestTimestamp);
void removeStickyThread(@NonNull ConversationId conversationId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ public void updateNotification(@NonNull Context context, @Nullable ConversationI
}

@Override
public void clearNotifications(@NonNull Context context) {
getNotifier().clearNotifications(context);
public boolean clearNotifications(@NonNull Context context) {
return getNotifier().clearNotifications(context);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,19 +241,23 @@ class DefaultMessageNotifier(context: Application) : MessageNotifier {

if (Build.VERSION.SDK_INT >= 24) {
val ids = state.conversations.filter { it.thread != visibleThread }.map { it.notificationId } + stickyThreads.map { (_, stickyThread) -> stickyThread.notificationId }
val notShown = ids - ServiceUtil.getNotificationManager(context).getDisplayedNotificationIds().getOrDefault(emptySet())
val notShown = ids - getDisplayedNotificationIds(context)
if (notShown.isNotEmpty()) {
Log.e(TAG, "Notifications should be showing but are not for ${notShown.size} threads")
}
}
}

override fun clearNotifications(context: Context) {
NotificationCancellationHelper.cancelAllMessageNotifications(context, stickyThreads.map { it.value.notificationId }.toSet())
override fun clearNotifications(context: Context): Boolean {
val activeNotifications = getDisplayedNotificationIds(context)
NotificationCancellationHelper.cancelAllMessageNotifications(context)
updateBadge(context, 0)
clearReminderInternal(context)
return activeNotifications.isNotEmpty()
}

private fun getDisplayedNotificationIds(context: Context) = ServiceUtil.getNotificationManager(context).getDisplayedNotificationIds().getOrDefault(emptySet())

override fun clearReminder(context: Context) {
// Intentionally left blank
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.ServiceUtil;
Expand All @@ -66,6 +65,8 @@ public class KeyCachingService extends Service {
public static final String CLEAR_KEY_ACTION = BuildConfig.APPLICATION_ID + ".service.action.CLEAR_KEY";
public static final String LOCALE_CHANGE_EVENT = BuildConfig.APPLICATION_ID + ".service.action.LOCALE_CHANGE_EVENT";

public static final String EXTRA_KEY_EXPIRED = "extra.key_expired";

private DynamicLanguage dynamicLanguage = new DynamicLanguage();

private final IBinder binder = new KeySetBinder();
Expand Down Expand Up @@ -110,9 +111,9 @@ public int onStartCommand(Intent intent, int flags, int startId) {

if (intent.getAction() != null) {
switch (intent.getAction()) {
case CLEAR_KEY_ACTION: handleClearKey(); break;
case PASSPHRASE_EXPIRED_EVENT: handleClearKey(); break;
case LOCALE_CHANGE_EVENT: handleLocaleChanged(); break;
case CLEAR_KEY_ACTION -> handleClearKey(false);
case PASSPHRASE_EXPIRED_EVENT -> handleClearKey(true);
case LOCALE_CHANGE_EVENT -> handleLocaleChanged();
}
} else {
handleCacheKey();
Expand Down Expand Up @@ -165,8 +166,8 @@ private void handleCacheKey() {
});
}

private void handleClearKey() {
Log.i(TAG, "handleClearKey");
private void handleClearKey(boolean keyExpired) {
Log.d(TAG, "handleClearKey() keyExpired: " + keyExpired);

cancelTimeout();

Expand All @@ -178,13 +179,12 @@ private void handleClearKey() {

KeyCachingService.locking = true;

sendPackageBroadcast(CLEAR_KEY_EVENT);
Log.i(TAG, "Broadcasting " + CLEAR_KEY_EVENT);

SignalExecutors.BOUNDED.execute(() -> {
MessageNotifier messageNotifier = ApplicationDependencies.getMessageNotifier();
messageNotifier.cancelDelayedNotifications();
messageNotifier.clearNotifications(KeyCachingService.this);
});
Intent intent = new Intent(CLEAR_KEY_EVENT);
intent.putExtra(EXTRA_KEY_EXPIRED, keyExpired);
intent.setPackage(getPackageName());
sendBroadcast(intent, KEY_PERMISSION);
}

private void handleLocaleChanged() {
Expand Down Expand Up @@ -252,18 +252,9 @@ private void foregroundService() {
startForeground(SERVICE_RUNNING_ID, builder.build());
}

private void sendPackageBroadcast(String action) {
Log.i(TAG, "Broadcasting " + action);

Intent intent = new Intent(action);
intent.setPackage(getApplicationContext().getPackageName());

sendBroadcast(intent, KEY_PERMISSION);
}

private PendingIntent buildLockIntent() {
Intent intent = new Intent(this, KeyCachingService.class);
intent.setAction(PASSPHRASE_EXPIRED_EVENT);
intent.setAction(CLEAR_KEY_ACTION);
return PendingIntent.getService(getApplicationContext(), 0, intent, getPendingIntentFlags());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.PowerManager;

import androidx.annotation.Nullable;
Expand All @@ -16,8 +15,8 @@
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.MainActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.gcm.FcmFetchManager;
import org.thoughtcrime.securesms.jobs.ForegroundServiceUtil;
import org.thoughtcrime.securesms.jobs.UnableToStartException;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.WakeLockUtil;
Expand Down Expand Up @@ -64,20 +63,8 @@ public class WipeMemoryService extends IntentService {

public static void run(Context context, boolean restartApp) {
restart = restartApp;
startForegroundService(context);
}

private static void startForegroundService(Context context) {
Intent intent = new Intent(context, WipeMemoryService.class);
if (Build.VERSION.SDK_INT >= 26) {
try {
ForegroundServiceUtil.startWhenCapable(context, intent);
} catch (UnableToStartException e) {
Log.e(TAG, "Unable to start foreground service", e);
}
} else {
context.startService(intent);
}
ForegroundServiceUtil.startWhenCapableOrThrow(context, intent);
}

public WipeMemoryService() {
Expand Down

0 comments on commit 7fba50a

Please sign in to comment.