SyncAlertStore.kt

3.4 KB · raw

1package com.peachpasswords.sync23import android.app.Notification4import android.app.NotificationChannel5import android.app.NotificationManager6import android.app.PendingIntent7import android.content.Context8import android.content.Intent9import androidx.core.app.NotificationCompat10import com.peachpasswords.MainActivity11import com.peachpasswords.R12import dagger.hilt.android.qualifiers.ApplicationContext13import javax.inject.Inject14import javax.inject.Singleton1516@Singleton17class SyncAlertStore @Inject constructor(18    @ApplicationContext private val context: Context,19) : SyncAlertRecorder {20    init {21        // v2.7.4 and earlier persisted security banners for the vault list.22        // They are intentionally not migrated into surprise notifications.23        context.deleteSharedPreferences(LEGACY_PREFS_FILE)24    }2526    override fun record(alerts: List<SyncAlert>) {27        // Final display seam: cap whatever name reached the queue.28        val capped = alerts.map { it.copy(deviceName = it.deviceName?.let(::capDeviceName)) }29        val content = syncSecurityNotificationContent(capped) ?: return30        val manager =31            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager32        runCatching {33            manager.notify(34                SYNC_SECURITY_NOTIFICATION_ID,35                buildSyncSecurityNotification(context, content),36            )37        }38    }3940    fun clear() {41        val manager =42            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager43        manager.cancel(SYNC_SECURITY_NOTIFICATION_ID)44    }45}4647internal const val SYNC_SECURITY_NOTIFICATION_CHANNEL_ID = "peach_sync_security"48internal const val SYNC_SECURITY_NOTIFICATION_ID = 420249private const val LEGACY_PREFS_FILE = "peach_sync_alerts"5051internal fun buildSyncSecurityNotification(52    context: Context,53    content: SyncSecurityNotificationContent,54): Notification {55    val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager56    manager.createNotificationChannel(57        NotificationChannel(58            SYNC_SECURITY_NOTIFICATION_CHANNEL_ID,59            "Peach Sync security",60            NotificationManager.IMPORTANCE_DEFAULT,61        ).apply {62            description = "Device removals and unexpected Peach Sync key changes."63        },64    )65    val open = PendingIntent.getActivity(66        context,67        0,68        Intent(context, MainActivity::class.java),69        PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,70    )71    val builder = NotificationCompat.Builder(context, SYNC_SECURITY_NOTIFICATION_CHANNEL_ID)72        .setContentTitle(content.title)73        .setContentText(content.summary)74        .setSmallIcon(R.drawable.ic_launcher_monochrome)75        .setPriority(NotificationCompat.PRIORITY_DEFAULT)76        .setCategory(NotificationCompat.CATEGORY_STATUS)77        .setVisibility(NotificationCompat.VISIBILITY_PRIVATE)78        .setAutoCancel(true)79        .setContentIntent(open)8081    if (content.lines.size == 1) {82        builder.setStyle(NotificationCompat.BigTextStyle().bigText(content.summary))83    } else {84        builder.setStyle(85            NotificationCompat.InboxStyle()86                .also { style -> content.lines.takeLast(5).forEach(style::addLine) }87                .setSummaryText("${content.lines.size} device security updates"),88        )89    }9091    return builder.build()92}