From f4a283567ea4c403d8f4665235e2ce359f31f938 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 11 Apr 2023 16:48:51 +0200 Subject: [PATCH] Cleanup store. --- .../libraries/push/api/store/PushDataStore.kt | 18 ---- .../NotificationDrawerManager.kt | 11 +-- .../notifications/NotificationEventQueue.kt | 1 + .../push/impl/push/DefaultPushHandler.kt | 23 +++-- .../push/impl/store/DefaultPushDataStore.kt | 96 ------------------- .../libraries/pushstore/api/UserPushStore.kt | 11 ++- .../pushstore/impl/UserPushStoreDataStore.kt | 17 ++++ 7 files changed, 40 insertions(+), 137 deletions(-) diff --git a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/store/PushDataStore.kt b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/store/PushDataStore.kt index d2a6bda0b0..f478034063 100644 --- a/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/store/PushDataStore.kt +++ b/libraries/push/api/src/main/kotlin/io/element/android/libraries/push/api/store/PushDataStore.kt @@ -16,26 +16,8 @@ package io.element.android.libraries.push.api.store -import io.element.android.libraries.push.api.model.BackgroundSyncMode import kotlinx.coroutines.flow.Flow interface PushDataStore { val pushCounterFlow: Flow - - // TODO Move all those settings to the per user store... - fun areNotificationEnabledForDevice(): Boolean - fun setNotificationEnabledForDevice(enabled: Boolean) - - fun backgroundSyncTimeOut(): Int - fun setBackgroundSyncTimeout(timeInSecond: Int) - fun backgroundSyncDelay(): Int - fun setBackgroundSyncDelay(timeInSecond: Int) - fun isBackgroundSyncEnabled(): Boolean - fun setFdroidSyncBackgroundMode(mode: BackgroundSyncMode) - fun getFdroidSyncBackgroundMode(): BackgroundSyncMode - - /** - * Return true if Pin code is disabled, or if user set the settings to see full notification content. - */ - fun useCompleteNotificationFormat(): Boolean } diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDrawerManager.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDrawerManager.kt index 8d3bfda4c3..cf0307fbd9 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDrawerManager.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationDrawerManager.kt @@ -70,7 +70,8 @@ class NotificationDrawerManager @Inject constructor( private var currentAppNavigationState: AppNavigationState? = null private val firstThrottler = FirstThrottler(200) - private var useCompleteNotificationFormat = pushDataStore.useCompleteNotificationFormat() + // TODO EAx add a setting per user for this + private var useCompleteNotificationFormat = true init { handlerThread.start() @@ -111,12 +112,6 @@ class NotificationDrawerManager @Inject constructor( } private fun NotificationEventQueue.onNotifiableEventReceived(notifiableEvent: NotifiableEvent) { - if (!pushDataStore.areNotificationEnabledForDevice()) { - Timber.i("Notification are disabled for this device") - return - } - // If we support multi session, event list should be per userId - // Currently only manage single session if (buildMeta.lowPrivacyLoggingEnabled) { Timber.d("onNotifiableEventReceived(): $notifiableEvent") } else { @@ -185,7 +180,7 @@ class NotificationDrawerManager @Inject constructor( // TODO EAx Must be per account fun notificationStyleChanged() { updateEvents { - val newSettings = pushDataStore.useCompleteNotificationFormat() + val newSettings = true // pushDataStore.useCompleteNotificationFormat() if (newSettings != useCompleteNotificationFormat) { // Settings has changed, remove all current notifications notificationRenderer.cancelAllNotifications() diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationEventQueue.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationEventQueue.kt index 60fb1baa05..862b4784ac 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationEventQueue.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationEventQueue.kt @@ -34,6 +34,7 @@ data class NotificationEventQueue constructor( * Acts as a notification debouncer to stop already dismissed push notifications from * displaying again when the /sync response is delayed. */ + // TODO Should be per session, so the key must be Pair. private val seenEventIds: CircularCache ) { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt index 7eef95fc67..09afe0a861 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt @@ -22,15 +22,12 @@ import android.os.Handler import android.os.Looper import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.squareup.anvil.annotations.ContributesBinding -import io.element.android.libraries.androidutils.network.WifiDetector import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService -import io.element.android.libraries.push.api.store.PushDataStore import io.element.android.libraries.push.impl.PushersManager -import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret import io.element.android.libraries.push.impl.log.pushLoggerTag import io.element.android.libraries.push.impl.notifications.NotifiableEventResolver import io.element.android.libraries.push.impl.notifications.NotificationActionIds @@ -38,6 +35,8 @@ import io.element.android.libraries.push.impl.notifications.NotificationDrawerMa import io.element.android.libraries.push.impl.store.DefaultPushDataStore import io.element.android.libraries.push.providers.api.PushData import io.element.android.libraries.push.providers.api.PushHandler +import io.element.android.libraries.pushstore.api.UserPushStoreFactory +import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -51,17 +50,16 @@ private val loggerTag = LoggerTag("PushHandler", pushLoggerTag) class DefaultPushHandler @Inject constructor( private val notificationDrawerManager: NotificationDrawerManager, private val notifiableEventResolver: NotifiableEventResolver, - private val pushDataStore: PushDataStore, private val defaultPushDataStore: DefaultPushDataStore, + private val userPushStoreFactory: UserPushStoreFactory, private val pushClientSecret: PushClientSecret, private val actionIds: NotificationActionIds, @ApplicationContext private val context: Context, private val buildMeta: BuildMeta, private val matrixAuthenticationService: MatrixAuthenticationService, -): PushHandler { +) : PushHandler { private val coroutineScope = CoroutineScope(SupervisorJob()) - private val wifiDetector: WifiDetector = WifiDetector(context) // UI handler private val mUIHandler by lazy { @@ -89,12 +87,6 @@ class DefaultPushHandler @Inject constructor( return } - // TODO EAx Should be per user - if (!pushDataStore.areNotificationEnabledForDevice()) { - Timber.tag(loggerTag.value).i("Notification are disabled for this device") - return - } - mUIHandler.post { coroutineScope.launch(Dispatchers.IO) { handleInternal(pushData) } } @@ -139,6 +131,13 @@ class DefaultPushHandler @Inject constructor( return } + val userPushStore = userPushStoreFactory.create(userId) + if (!userPushStore.areNotificationEnabledForDevice()) { + // TODO We need to check if this is an incoming call + Timber.tag(loggerTag.value).i("Notification are disabled for this device, ignore push.") + return + } + notificationDrawerManager.onNotifiableEventReceived(notificationData) } catch (e: Exception) { Timber.tag(loggerTag.value).e(e, "## handleInternal() failed") diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/store/DefaultPushDataStore.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/store/DefaultPushDataStore.kt index ffbd575aa4..22faa91453 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/store/DefaultPushDataStore.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/store/DefaultPushDataStore.kt @@ -17,20 +17,15 @@ package io.element.android.libraries.push.impl.store import android.content.Context -import android.content.SharedPreferences -import androidx.core.content.edit import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.intPreferencesKey import androidx.datastore.preferences.preferencesDataStore import com.squareup.anvil.annotations.ContributesBinding -import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext -import io.element.android.libraries.di.DefaultPreferences import io.element.android.libraries.di.SingleIn -import io.element.android.libraries.push.api.model.BackgroundSyncMode import io.element.android.libraries.push.api.store.PushDataStore import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map @@ -42,7 +37,6 @@ private val Context.dataStore: DataStore by preferencesDataStore(na @ContributesBinding(AppScope::class) class DefaultPushDataStore @Inject constructor( @ApplicationContext private val context: Context, - @DefaultPreferences private val defaultPrefs: SharedPreferences, ) : PushDataStore { private val pushCounter = intPreferencesKey("push_counter") @@ -56,94 +50,4 @@ class DefaultPushDataStore @Inject constructor( settings[pushCounter] = currentCounterValue + 1 } } - - override fun areNotificationEnabledForDevice(): Boolean { - return defaultPrefs.getBoolean(SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY, true) - } - - override fun setNotificationEnabledForDevice(enabled: Boolean) { - defaultPrefs.edit { - putBoolean(SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY, enabled) - } - } - - override fun backgroundSyncTimeOut(): Int { - return tryOrNull { - // The xml pref is saved as a string so use getString and parse - defaultPrefs.getString(SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY, null)?.toInt() - } ?: BackgroundSyncMode.DEFAULT_SYNC_TIMEOUT_SECONDS - } - - override fun setBackgroundSyncTimeout(timeInSecond: Int) { - defaultPrefs - .edit() - .putString(SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY, timeInSecond.toString()) - .apply() - } - - override fun backgroundSyncDelay(): Int { - return tryOrNull { - // The xml pref is saved as a string so use getString and parse - defaultPrefs.getString(SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY, null)?.toInt() - } ?: BackgroundSyncMode.DEFAULT_SYNC_DELAY_SECONDS - } - - override fun setBackgroundSyncDelay(timeInSecond: Int) { - defaultPrefs - .edit() - .putString(SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY, timeInSecond.toString()) - .apply() - } - - override fun isBackgroundSyncEnabled(): Boolean { - return getFdroidSyncBackgroundMode() != BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED - } - - override fun setFdroidSyncBackgroundMode(mode: BackgroundSyncMode) { - defaultPrefs - .edit() - .putString(SETTINGS_FDROID_BACKGROUND_SYNC_MODE, mode.name) - .apply() - } - - override fun getFdroidSyncBackgroundMode(): BackgroundSyncMode { - return try { - val strPref = defaultPrefs - .getString(SETTINGS_FDROID_BACKGROUND_SYNC_MODE, BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY.name) - BackgroundSyncMode.values().firstOrNull { it.name == strPref } ?: BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY - } catch (e: Throwable) { - BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY - } - } - - /** - * Return true if Pin code is disabled, or if user set the settings to see full notification content. - */ - override fun useCompleteNotificationFormat(): Boolean { - return true - /* - return !useFlagPinCode() || - defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_COMPLETE_NOTIFICATIONS_FLAG, true) - */ - } - - companion object { - // notifications - const val SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY = "SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY" - const val SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY = "SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY" - - // background sync - const val SETTINGS_START_ON_BOOT_PREFERENCE_KEY = "SETTINGS_START_ON_BOOT_PREFERENCE_KEY" - const val SETTINGS_ENABLE_BACKGROUND_SYNC_PREFERENCE_KEY = "SETTINGS_ENABLE_BACKGROUND_SYNC_PREFERENCE_KEY" - const val SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY = "SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY" - const val SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY = "SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY" - - const val SETTINGS_FDROID_BACKGROUND_SYNC_MODE = "SETTINGS_FDROID_BACKGROUND_SYNC_MODE" - const val SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY = "SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY" - - const val SETTINGS_SECURITY_USE_COMPLETE_NOTIFICATIONS_FLAG = "SETTINGS_SECURITY_USE_COMPLETE_NOTIFICATIONS_FLAG" - - // notification method - const val SETTINGS_NOTIFICATION_METHOD_KEY = "SETTINGS_NOTIFICATION_METHOD_KEY" - } } diff --git a/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt b/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt index 6817199e13..28577ba3f8 100644 --- a/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt +++ b/libraries/pushstore/api/src/main/kotlin/io/element/android/libraries/pushstore/api/UserPushStore.kt @@ -21,12 +21,17 @@ package io.element.android.libraries.pushstore.api */ interface UserPushStore { suspend fun getPushProviderName(): String? - suspend fun setPushProviderName(value: String) - suspend fun getCurrentRegisteredPushKey(): String? - suspend fun setCurrentRegisteredPushKey(value: String) + suspend fun areNotificationEnabledForDevice(): Boolean + suspend fun setNotificationEnabledForDevice(enabled: Boolean) + + /** + * Return true if Pin code is disabled, or if user set the settings to see full notification content. + */ + fun useCompleteNotificationFormat(): Boolean + suspend fun reset() } diff --git a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt index c7a320f085..56867a6584 100644 --- a/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt +++ b/libraries/pushstore/impl/src/main/kotlin/io/element/android/libraries/pushstore/impl/UserPushStoreDataStore.kt @@ -19,9 +19,11 @@ package io.element.android.libraries.pushstore.impl import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore +import io.element.android.libraries.core.bool.orTrue import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.pushstore.api.UserPushStore import kotlinx.coroutines.flow.first @@ -36,6 +38,7 @@ class UserPushStoreDataStore( private val Context.dataStore: DataStore by preferencesDataStore(name = "push_store_$userId") private val pushProviderName = stringPreferencesKey("pushProviderName") private val currentPushKey = stringPreferencesKey("currentPushKey") + private val notificationEnabled = booleanPreferencesKey("notificationEnabled") override suspend fun getPushProviderName(): String? { return context.dataStore.data.first()[pushProviderName] @@ -57,6 +60,20 @@ class UserPushStoreDataStore( } } + override suspend fun areNotificationEnabledForDevice(): Boolean { + return context.dataStore.data.first()[notificationEnabled].orTrue() + } + + override suspend fun setNotificationEnabledForDevice(enabled: Boolean) { + context.dataStore.edit { + it[notificationEnabled] = enabled + } + } + + override fun useCompleteNotificationFormat(): Boolean { + return true + } + override suspend fun reset() { context.dataStore.edit { it.clear()