Merge pull request #5645 from element-hq/feature/bma/mutliAccountNotification
Improve rendering notification for multi account
This commit is contained in:
commit
37f10ced4a
34 changed files with 464 additions and 433 deletions
|
|
@ -93,6 +93,7 @@ dependencies {
|
||||||
testImplementation(projects.libraries.featureflag.test)
|
testImplementation(projects.libraries.featureflag.test)
|
||||||
testImplementation(projects.libraries.preferences.test)
|
testImplementation(projects.libraries.preferences.test)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
|
testImplementation(projects.libraries.matrixuiTest)
|
||||||
testImplementation(projects.libraries.push.test)
|
testImplementation(projects.libraries.push.test)
|
||||||
testImplementation(projects.services.analytics.test)
|
testImplementation(projects.services.analytics.test)
|
||||||
testImplementation(projects.services.appnavstate.test)
|
testImplementation(projects.services.appnavstate.test)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||||
import io.element.android.libraries.push.test.notifications.FakeImageLoaderHolder
|
import io.element.android.libraries.matrix.ui.test.media.FakeImageLoaderHolder
|
||||||
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||||
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||||
|
import io.element.android.libraries.matrix.ui.test.media.FakeImageLoaderHolder
|
||||||
import io.element.android.libraries.push.api.notifications.ForegroundServiceType
|
import io.element.android.libraries.push.api.notifications.ForegroundServiceType
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
||||||
import io.element.android.libraries.push.test.notifications.FakeImageLoaderHolder
|
|
||||||
import io.element.android.libraries.push.test.notifications.FakeOnMissedCallNotificationHandler
|
import io.element.android.libraries.push.test.notifications.FakeOnMissedCallNotificationHandler
|
||||||
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
||||||
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
|
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
|
||||||
|
|
@ -415,6 +415,7 @@ class DefaultActiveCallManagerTest {
|
||||||
|
|
||||||
verify { notificationManagerCompat.cancel(any()) }
|
verify { notificationManagerCompat.cancel(any()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@Test
|
@Test
|
||||||
fun `IncomingCall - ignore expired ring lifetime`() = runTest {
|
fun `IncomingCall - ignore expired ring lifetime`() = runTest {
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,12 @@ class FakeEnterpriseService(
|
||||||
private val defaultHomeserverListResult: () -> List<String> = { emptyList() },
|
private val defaultHomeserverListResult: () -> List<String> = { emptyList() },
|
||||||
private val isAllowedToConnectToHomeserverResult: (String) -> Boolean = { lambdaError() },
|
private val isAllowedToConnectToHomeserverResult: (String) -> Boolean = { lambdaError() },
|
||||||
initialSemanticColors: SemanticColorsLightDark = SemanticColorsLightDark.default,
|
initialSemanticColors: SemanticColorsLightDark = SemanticColorsLightDark.default,
|
||||||
|
initialBrandColor: Color? = null,
|
||||||
private val overrideBrandColorResult: (SessionId?, String?) -> Unit = { _, _ -> lambdaError() },
|
private val overrideBrandColorResult: (SessionId?, String?) -> Unit = { _, _ -> lambdaError() },
|
||||||
private val firebasePushGatewayResult: () -> String? = { lambdaError() },
|
private val firebasePushGatewayResult: () -> String? = { lambdaError() },
|
||||||
private val unifiedPushDefaultPushGatewayResult: () -> String? = { lambdaError() },
|
private val unifiedPushDefaultPushGatewayResult: () -> String? = { lambdaError() },
|
||||||
) : EnterpriseService {
|
) : EnterpriseService {
|
||||||
private val brandColorState = MutableStateFlow<Color?>(null)
|
private val brandColorState = MutableStateFlow(initialBrandColor)
|
||||||
private val semanticColorsState = MutableStateFlow(initialSemanticColors)
|
private val semanticColorsState = MutableStateFlow(initialSemanticColors)
|
||||||
|
|
||||||
override suspend fun isEnterpriseUser(sessionId: SessionId): Boolean = simulateLongTask {
|
override suspend fun isEnterpriseUser(sessionId: SessionId): Boolean = simulateLongTask {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.test
|
package io.element.android.libraries.matrix.test
|
||||||
|
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
|
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
|
||||||
import io.element.android.libraries.matrix.api.core.DeviceId
|
import io.element.android.libraries.matrix.api.core.DeviceId
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
|
@ -99,4 +100,5 @@ const val A_FORMATTED_DATE = "April 6, 1980 at 6:35 PM"
|
||||||
|
|
||||||
const val A_LOGIN_HINT = "mxid:@alice:example.org"
|
const val A_LOGIN_HINT = "mxid:@alice:example.org"
|
||||||
|
|
||||||
const val A_COLOR_INT = 0xFF0000
|
@ColorInt
|
||||||
|
const val A_COLOR_INT: Int = 0xFFFF0000.toInt()
|
||||||
|
|
|
||||||
20
libraries/matrixui-test/build.gradle.kts
Normal file
20
libraries/matrixui-test/build.gradle.kts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("io.element.android-library")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "io.element.android.libraries.matrix.ui.test"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(projects.libraries.matrix.api)
|
||||||
|
implementation(projects.libraries.matrixui)
|
||||||
|
implementation(libs.coil.compose)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.ui.test.media
|
||||||
|
|
||||||
|
import coil3.ComponentRegistry
|
||||||
|
import coil3.ImageLoader
|
||||||
|
import coil3.disk.DiskCache
|
||||||
|
import coil3.memory.MemoryCache
|
||||||
|
import coil3.request.Disposable
|
||||||
|
import coil3.request.ImageRequest
|
||||||
|
import coil3.request.ImageResult
|
||||||
|
|
||||||
|
class FakeImageLoader : ImageLoader {
|
||||||
|
private val executedRequests = mutableListOf<ImageRequest>()
|
||||||
|
|
||||||
|
override val defaults: ImageRequest.Defaults
|
||||||
|
get() = error("Not implemented")
|
||||||
|
override val components: ComponentRegistry
|
||||||
|
get() = error("Not implemented")
|
||||||
|
override val memoryCache: MemoryCache?
|
||||||
|
get() = error("Not implemented")
|
||||||
|
override val diskCache: DiskCache?
|
||||||
|
get() = error("Not implemented")
|
||||||
|
|
||||||
|
override fun enqueue(request: ImageRequest): Disposable {
|
||||||
|
error("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun execute(request: ImageRequest): ImageResult {
|
||||||
|
executedRequests.add(request)
|
||||||
|
error("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shutdown() {
|
||||||
|
error("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newBuilder(): ImageLoader.Builder {
|
||||||
|
error("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getExecutedRequestsData(): List<Any> {
|
||||||
|
return executedRequests.map { it.data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,21 +1,22 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2024 New Vector Ltd.
|
* Copyright 2025 New Vector Ltd.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
* Please see LICENSE files in the repository root for full details.
|
* Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.push.test.notifications
|
package io.element.android.libraries.matrix.ui.test.media
|
||||||
|
|
||||||
import coil3.ImageLoader
|
import coil3.ImageLoader
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
|
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
|
||||||
|
|
||||||
class FakeImageLoaderHolder : ImageLoaderHolder {
|
class FakeImageLoaderHolder(
|
||||||
private val fakeImageLoader = FakeImageLoader()
|
val fakeImageLoader: ImageLoader = FakeImageLoader(),
|
||||||
|
) : ImageLoaderHolder {
|
||||||
override fun get(client: MatrixClient): ImageLoader {
|
override fun get(client: MatrixClient): ImageLoader {
|
||||||
return fakeImageLoader.getImageLoader()
|
return fakeImageLoader
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun remove(sessionId: SessionId) {
|
override fun remove(sessionId: SessionId) {
|
||||||
|
|
@ -76,6 +76,7 @@ dependencies {
|
||||||
testCommonDependencies(libs)
|
testCommonDependencies(libs)
|
||||||
testImplementation(libs.coil.test)
|
testImplementation(libs.coil.test)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
|
testImplementation(projects.libraries.matrixuiTest)
|
||||||
testImplementation(projects.libraries.preferences.test)
|
testImplementation(projects.libraries.preferences.test)
|
||||||
testImplementation(projects.libraries.sessionStorage.test)
|
testImplementation(projects.libraries.sessionStorage.test)
|
||||||
testImplementation(projects.libraries.push.test)
|
testImplementation(projects.libraries.push.test)
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,10 @@
|
||||||
|
|
||||||
package io.element.android.libraries.push.impl.notifications
|
package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import dev.zacsweers.metro.AppScope
|
import dev.zacsweers.metro.AppScope
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import dev.zacsweers.metro.SingleIn
|
import dev.zacsweers.metro.SingleIn
|
||||||
import io.element.android.libraries.core.data.tryOrNull
|
|
||||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
|
||||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
|
||||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
|
@ -32,11 +27,7 @@ import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
import io.element.android.services.appnavstate.api.NavigationState
|
import io.element.android.services.appnavstate.api.NavigationState
|
||||||
import io.element.android.services.appnavstate.api.currentSessionId
|
import io.element.android.services.appnavstate.api.currentSessionId
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
private val loggerTag = LoggerTag("DefaultNotificationDrawerManager", LoggerTag.NotificationLoggerTag)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class receives notification events as they arrive from the PushHandler calling [onNotifiableEventReceived] and
|
* This class receives notification events as they arrive from the PushHandler calling [onNotifiableEventReceived] and
|
||||||
|
|
@ -46,7 +37,7 @@ private val loggerTag = LoggerTag("DefaultNotificationDrawerManager", LoggerTag.
|
||||||
@SingleIn(AppScope::class)
|
@SingleIn(AppScope::class)
|
||||||
@ContributesBinding(AppScope::class)
|
@ContributesBinding(AppScope::class)
|
||||||
class DefaultNotificationDrawerManager(
|
class DefaultNotificationDrawerManager(
|
||||||
private val notificationManager: NotificationManagerCompat,
|
private val notificationDisplayer: NotificationDisplayer,
|
||||||
private val notificationRenderer: NotificationRenderer,
|
private val notificationRenderer: NotificationRenderer,
|
||||||
private val appNavigationStateService: AppNavigationStateService,
|
private val appNavigationStateService: AppNavigationStateService,
|
||||||
@AppCoroutineScope
|
@AppCoroutineScope
|
||||||
|
|
@ -55,25 +46,17 @@ class DefaultNotificationDrawerManager(
|
||||||
private val imageLoaderHolder: ImageLoaderHolder,
|
private val imageLoaderHolder: ImageLoaderHolder,
|
||||||
private val activeNotificationsProvider: ActiveNotificationsProvider,
|
private val activeNotificationsProvider: ActiveNotificationsProvider,
|
||||||
) : NotificationCleaner {
|
) : NotificationCleaner {
|
||||||
private var appNavigationStateObserver: Job? = null
|
|
||||||
|
|
||||||
// TODO EAx add a setting per user for this
|
// TODO EAx add a setting per user for this
|
||||||
private var useCompleteNotificationFormat = true
|
private var useCompleteNotificationFormat = true
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Observe application state
|
// Observe application state
|
||||||
appNavigationStateObserver = coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
appNavigationStateService.appNavigationState
|
appNavigationStateService.appNavigationState
|
||||||
.collect { onAppNavigationStateChange(it.navigationState) }
|
.collect { onAppNavigationStateChange(it.navigationState) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For test only
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
|
||||||
internal fun destroy() {
|
|
||||||
appNavigationStateObserver?.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
private var currentAppNavigationState: NavigationState? = null
|
private var currentAppNavigationState: NavigationState? = null
|
||||||
|
|
||||||
private fun onAppNavigationStateChange(navigationState: NavigationState) {
|
private fun onAppNavigationStateChange(navigationState: NavigationState) {
|
||||||
|
|
@ -124,7 +107,7 @@ class DefaultNotificationDrawerManager(
|
||||||
* Clear all known message events for a [sessionId].
|
* Clear all known message events for a [sessionId].
|
||||||
*/
|
*/
|
||||||
override fun clearAllMessagesEvents(sessionId: SessionId) {
|
override fun clearAllMessagesEvents(sessionId: SessionId) {
|
||||||
notificationManager.cancel(null, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
notificationDisplayer.cancelNotification(null, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||||
clearSummaryNotificationIfNeeded(sessionId)
|
clearSummaryNotificationIfNeeded(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,7 +116,7 @@ class DefaultNotificationDrawerManager(
|
||||||
*/
|
*/
|
||||||
fun clearAllEvents(sessionId: SessionId) {
|
fun clearAllEvents(sessionId: SessionId) {
|
||||||
activeNotificationsProvider.getNotificationsForSession(sessionId)
|
activeNotificationsProvider.getNotificationsForSession(sessionId)
|
||||||
.forEach { notificationManager.cancel(it.tag, it.id) }
|
.forEach { notificationDisplayer.cancelNotification(it.tag, it.id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -142,7 +125,7 @@ class DefaultNotificationDrawerManager(
|
||||||
* Can also be called when a notification for this room is dismissed by the user.
|
* Can also be called when a notification for this room is dismissed by the user.
|
||||||
*/
|
*/
|
||||||
override fun clearMessagesForRoom(sessionId: SessionId, roomId: RoomId) {
|
override fun clearMessagesForRoom(sessionId: SessionId, roomId: RoomId) {
|
||||||
notificationManager.cancel(roomId.value, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
notificationDisplayer.cancelNotification(roomId.value, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||||
clearSummaryNotificationIfNeeded(sessionId)
|
clearSummaryNotificationIfNeeded(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,13 +135,13 @@ class DefaultNotificationDrawerManager(
|
||||||
*/
|
*/
|
||||||
override fun clearMessagesForThread(sessionId: SessionId, roomId: RoomId, threadId: ThreadId) {
|
override fun clearMessagesForThread(sessionId: SessionId, roomId: RoomId, threadId: ThreadId) {
|
||||||
val tag = NotificationCreator.messageTag(roomId, threadId)
|
val tag = NotificationCreator.messageTag(roomId, threadId)
|
||||||
notificationManager.cancel(tag, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
notificationDisplayer.cancelNotification(tag, NotificationIdProvider.getRoomMessagesNotificationId(sessionId))
|
||||||
clearSummaryNotificationIfNeeded(sessionId)
|
clearSummaryNotificationIfNeeded(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clearMembershipNotificationForSession(sessionId: SessionId) {
|
override fun clearMembershipNotificationForSession(sessionId: SessionId) {
|
||||||
activeNotificationsProvider.getMembershipNotificationForSession(sessionId)
|
activeNotificationsProvider.getMembershipNotificationForSession(sessionId)
|
||||||
.forEach { notificationManager.cancel(it.tag, it.id) }
|
.forEach { notificationDisplayer.cancelNotification(it.tag, it.id) }
|
||||||
clearSummaryNotificationIfNeeded(sessionId)
|
clearSummaryNotificationIfNeeded(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,7 +150,7 @@ class DefaultNotificationDrawerManager(
|
||||||
*/
|
*/
|
||||||
override fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId) {
|
override fun clearMembershipNotificationForRoom(sessionId: SessionId, roomId: RoomId) {
|
||||||
activeNotificationsProvider.getMembershipNotificationForRoom(sessionId, roomId)
|
activeNotificationsProvider.getMembershipNotificationForRoom(sessionId, roomId)
|
||||||
.forEach { notificationManager.cancel(it.tag, it.id) }
|
.forEach { notificationDisplayer.cancelNotification(it.tag, it.id) }
|
||||||
clearSummaryNotificationIfNeeded(sessionId)
|
clearSummaryNotificationIfNeeded(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,14 +159,14 @@ class DefaultNotificationDrawerManager(
|
||||||
*/
|
*/
|
||||||
override fun clearEvent(sessionId: SessionId, eventId: EventId) {
|
override fun clearEvent(sessionId: SessionId, eventId: EventId) {
|
||||||
val id = NotificationIdProvider.getRoomEventNotificationId(sessionId)
|
val id = NotificationIdProvider.getRoomEventNotificationId(sessionId)
|
||||||
notificationManager.cancel(eventId.value, id)
|
notificationDisplayer.cancelNotification(eventId.value, id)
|
||||||
clearSummaryNotificationIfNeeded(sessionId)
|
clearSummaryNotificationIfNeeded(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clearSummaryNotificationIfNeeded(sessionId: SessionId) {
|
private fun clearSummaryNotificationIfNeeded(sessionId: SessionId) {
|
||||||
val summaryNotification = activeNotificationsProvider.getSummaryNotification(sessionId)
|
val summaryNotification = activeNotificationsProvider.getSummaryNotification(sessionId)
|
||||||
if (summaryNotification != null && activeNotificationsProvider.count(sessionId) == 1) {
|
if (summaryNotification != null && activeNotificationsProvider.count(sessionId) == 1) {
|
||||||
notificationManager.cancel(null, summaryNotification.id)
|
notificationDisplayer.cancelNotification(null, summaryNotification.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,29 +184,9 @@ class DefaultNotificationDrawerManager(
|
||||||
// We have an avatar and a display name, use it
|
// We have an avatar and a display name, use it
|
||||||
userFromCache
|
userFromCache
|
||||||
} else {
|
} else {
|
||||||
client.getSafeUserProfile()
|
client.getUserProfile().getOrNull() ?: MatrixUser(sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationRenderer.render(currentUser, useCompleteNotificationFormat, notifiableEvents, imageLoader)
|
notificationRenderer.render(currentUser, useCompleteNotificationFormat, notifiableEvents, imageLoader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun MatrixClient.getSafeUserProfile(): MatrixUser {
|
|
||||||
return tryOrNull(
|
|
||||||
onException = { Timber.tag(loggerTag.value).e(it, "Unable to retrieve info for user ${sessionId.value}") },
|
|
||||||
operation = {
|
|
||||||
val profile = getUserProfile().getOrNull()
|
|
||||||
// displayName cannot be empty else NotificationCompat.MessagingStyle() will crash
|
|
||||||
if (profile?.displayName.isNullOrEmpty()) {
|
|
||||||
profile?.copy(displayName = sessionId.value)
|
|
||||||
} else {
|
|
||||||
profile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) ?: MatrixUser(
|
|
||||||
userId = sessionId,
|
|
||||||
displayName = sessionId.value,
|
|
||||||
avatarUrl = null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ package io.element.android.libraries.push.impl.notifications
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.text.style.StyleSpan
|
import android.text.style.StyleSpan
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import androidx.core.text.buildSpannedString
|
import androidx.core.text.buildSpannedString
|
||||||
import androidx.core.text.inSpans
|
import androidx.core.text.inSpans
|
||||||
import coil3.ImageLoader
|
import coil3.ImageLoader
|
||||||
|
|
@ -19,8 +18,8 @@ import dev.zacsweers.metro.ContributesBinding
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
|
||||||
import io.element.android.libraries.push.impl.R
|
import io.element.android.libraries.push.impl.R
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||||
|
|
@ -31,39 +30,37 @@ import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
interface NotificationDataFactory {
|
interface NotificationDataFactory {
|
||||||
suspend fun toNotifications(
|
suspend fun toNotifications(
|
||||||
messages: List<NotifiableMessageEvent>,
|
messages: List<NotifiableMessageEvent>,
|
||||||
currentUser: MatrixUser,
|
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<RoomNotification>
|
): List<RoomNotification>
|
||||||
|
|
||||||
@JvmName("toNotificationInvites")
|
@JvmName("toNotificationInvites")
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
fun toNotifications(
|
fun toNotifications(
|
||||||
invites: List<InviteNotifiableEvent>,
|
invites: List<InviteNotifiableEvent>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<OneShotNotification>
|
): List<OneShotNotification>
|
||||||
|
|
||||||
@JvmName("toNotificationSimpleEvents")
|
@JvmName("toNotificationSimpleEvents")
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
fun toNotifications(
|
fun toNotifications(
|
||||||
simpleEvents: List<SimpleNotifiableEvent>,
|
simpleEvents: List<SimpleNotifiableEvent>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<OneShotNotification>
|
): List<OneShotNotification>
|
||||||
|
|
||||||
@JvmName("toNotificationFallbackEvents")
|
@JvmName("toNotificationFallbackEvents")
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
fun toNotifications(
|
fun toNotifications(
|
||||||
fallback: List<FallbackNotifiableEvent>,
|
fallback: List<FallbackNotifiableEvent>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<OneShotNotification>
|
): List<OneShotNotification>
|
||||||
|
|
||||||
fun createSummaryNotification(
|
fun createSummaryNotification(
|
||||||
currentUser: MatrixUser,
|
|
||||||
roomNotifications: List<RoomNotification>,
|
roomNotifications: List<RoomNotification>,
|
||||||
invitationNotifications: List<OneShotNotification>,
|
invitationNotifications: List<OneShotNotification>,
|
||||||
simpleNotifications: List<OneShotNotification>,
|
simpleNotifications: List<OneShotNotification>,
|
||||||
fallbackNotifications: List<OneShotNotification>,
|
fallbackNotifications: List<OneShotNotification>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): SummaryNotification
|
): SummaryNotification
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,9 +74,8 @@ class DefaultNotificationDataFactory(
|
||||||
) : NotificationDataFactory {
|
) : NotificationDataFactory {
|
||||||
override suspend fun toNotifications(
|
override suspend fun toNotifications(
|
||||||
messages: List<NotifiableMessageEvent>,
|
messages: List<NotifiableMessageEvent>,
|
||||||
currentUser: MatrixUser,
|
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<RoomNotification> {
|
): List<RoomNotification> {
|
||||||
val messagesToDisplay = messages.filterNot { it.canNotBeDisplayed() }
|
val messagesToDisplay = messages.filterNot { it.canNotBeDisplayed() }
|
||||||
.groupBy { it.roomId }
|
.groupBy { it.roomId }
|
||||||
|
|
@ -90,13 +86,12 @@ class DefaultNotificationDataFactory(
|
||||||
|
|
||||||
eventsByThreadId.map { (threadId, events) ->
|
eventsByThreadId.map { (threadId, events) ->
|
||||||
val notification = roomGroupMessageCreator.createRoomMessage(
|
val notification = roomGroupMessageCreator.createRoomMessage(
|
||||||
currentUser = currentUser,
|
|
||||||
events = events,
|
events = events,
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
threadId = threadId,
|
threadId = threadId,
|
||||||
imageLoader = imageLoader,
|
imageLoader = imageLoader,
|
||||||
existingNotification = getExistingNotificationForMessages(currentUser.userId, roomId, threadId),
|
existingNotification = getExistingNotificationForMessages(notificationAccountParams.user.userId, roomId, threadId),
|
||||||
color = color,
|
notificationAccountParams = notificationAccountParams,
|
||||||
)
|
)
|
||||||
RoomNotification(
|
RoomNotification(
|
||||||
notification = notification,
|
notification = notification,
|
||||||
|
|
@ -121,12 +116,12 @@ class DefaultNotificationDataFactory(
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
override fun toNotifications(
|
override fun toNotifications(
|
||||||
invites: List<InviteNotifiableEvent>,
|
invites: List<InviteNotifiableEvent>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<OneShotNotification> {
|
): List<OneShotNotification> {
|
||||||
return invites.map { event ->
|
return invites.map { event ->
|
||||||
OneShotNotification(
|
OneShotNotification(
|
||||||
key = event.roomId.value,
|
tag = event.roomId.value,
|
||||||
notification = notificationCreator.createRoomInvitationNotification(event, color),
|
notification = notificationCreator.createRoomInvitationNotification(notificationAccountParams, event),
|
||||||
summaryLine = event.description,
|
summaryLine = event.description,
|
||||||
isNoisy = event.noisy,
|
isNoisy = event.noisy,
|
||||||
timestamp = event.timestamp
|
timestamp = event.timestamp
|
||||||
|
|
@ -138,12 +133,12 @@ class DefaultNotificationDataFactory(
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
override fun toNotifications(
|
override fun toNotifications(
|
||||||
simpleEvents: List<SimpleNotifiableEvent>,
|
simpleEvents: List<SimpleNotifiableEvent>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<OneShotNotification> {
|
): List<OneShotNotification> {
|
||||||
return simpleEvents.map { event ->
|
return simpleEvents.map { event ->
|
||||||
OneShotNotification(
|
OneShotNotification(
|
||||||
key = event.eventId.value,
|
tag = event.eventId.value,
|
||||||
notification = notificationCreator.createSimpleEventNotification(event, color),
|
notification = notificationCreator.createSimpleEventNotification(notificationAccountParams, event),
|
||||||
summaryLine = event.description,
|
summaryLine = event.description,
|
||||||
isNoisy = event.noisy,
|
isNoisy = event.noisy,
|
||||||
timestamp = event.timestamp
|
timestamp = event.timestamp
|
||||||
|
|
@ -155,12 +150,12 @@ class DefaultNotificationDataFactory(
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
override fun toNotifications(
|
override fun toNotifications(
|
||||||
fallback: List<FallbackNotifiableEvent>,
|
fallback: List<FallbackNotifiableEvent>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<OneShotNotification> {
|
): List<OneShotNotification> {
|
||||||
return fallback.map { event ->
|
return fallback.map { event ->
|
||||||
OneShotNotification(
|
OneShotNotification(
|
||||||
key = event.eventId.value,
|
tag = event.eventId.value,
|
||||||
notification = notificationCreator.createFallbackNotification(event, color),
|
notification = notificationCreator.createFallbackNotification(notificationAccountParams, event),
|
||||||
summaryLine = event.description.orEmpty(),
|
summaryLine = event.description.orEmpty(),
|
||||||
isNoisy = false,
|
isNoisy = false,
|
||||||
timestamp = event.timestamp
|
timestamp = event.timestamp
|
||||||
|
|
@ -169,23 +164,21 @@ class DefaultNotificationDataFactory(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createSummaryNotification(
|
override fun createSummaryNotification(
|
||||||
currentUser: MatrixUser,
|
|
||||||
roomNotifications: List<RoomNotification>,
|
roomNotifications: List<RoomNotification>,
|
||||||
invitationNotifications: List<OneShotNotification>,
|
invitationNotifications: List<OneShotNotification>,
|
||||||
simpleNotifications: List<OneShotNotification>,
|
simpleNotifications: List<OneShotNotification>,
|
||||||
fallbackNotifications: List<OneShotNotification>,
|
fallbackNotifications: List<OneShotNotification>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): SummaryNotification {
|
): SummaryNotification {
|
||||||
return when {
|
return when {
|
||||||
roomNotifications.isEmpty() && invitationNotifications.isEmpty() && simpleNotifications.isEmpty() -> SummaryNotification.Removed
|
roomNotifications.isEmpty() && invitationNotifications.isEmpty() && simpleNotifications.isEmpty() -> SummaryNotification.Removed
|
||||||
else -> SummaryNotification.Update(
|
else -> SummaryNotification.Update(
|
||||||
summaryGroupMessageCreator.createSummaryNotification(
|
summaryGroupMessageCreator.createSummaryNotification(
|
||||||
currentUser = currentUser,
|
|
||||||
roomNotifications = roomNotifications,
|
roomNotifications = roomNotifications,
|
||||||
invitationNotifications = invitationNotifications,
|
invitationNotifications = invitationNotifications,
|
||||||
simpleNotifications = simpleNotifications,
|
simpleNotifications = simpleNotifications,
|
||||||
fallbackNotifications = fallbackNotifications,
|
fallbackNotifications = fallbackNotifications,
|
||||||
color = color,
|
notificationAccountParams = notificationAccountParams,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -254,7 +247,7 @@ data class RoomNotification(
|
||||||
|
|
||||||
data class OneShotNotification(
|
data class OneShotNotification(
|
||||||
val notification: Notification,
|
val notification: Notification,
|
||||||
val key: String,
|
val tag: String,
|
||||||
val summaryLine: CharSequence,
|
val summaryLine: CharSequence,
|
||||||
val isNoisy: Boolean,
|
val isNoisy: Boolean,
|
||||||
val timestamp: Long,
|
val timestamp: Long,
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ import io.element.android.libraries.di.annotations.ApplicationContext
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
interface NotificationDisplayer {
|
interface NotificationDisplayer {
|
||||||
fun showNotificationMessage(tag: String?, id: Int, notification: Notification): Boolean
|
fun showNotification(tag: String?, id: Int, notification: Notification): Boolean
|
||||||
fun cancelNotificationMessage(tag: String?, id: Int)
|
fun cancelNotification(tag: String?, id: Int)
|
||||||
fun displayDiagnosticNotification(notification: Notification): Boolean
|
fun displayDiagnosticNotification(notification: Notification): Boolean
|
||||||
fun dismissDiagnosticNotification()
|
fun dismissDiagnosticNotification()
|
||||||
}
|
}
|
||||||
|
|
@ -30,7 +30,7 @@ class DefaultNotificationDisplayer(
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
private val notificationManager: NotificationManagerCompat
|
private val notificationManager: NotificationManagerCompat
|
||||||
) : NotificationDisplayer {
|
) : NotificationDisplayer {
|
||||||
override fun showNotificationMessage(tag: String?, id: Int, notification: Notification): Boolean {
|
override fun showNotification(tag: String?, id: Int, notification: Notification): Boolean {
|
||||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||||
Timber.w("Not allowed to notify.")
|
Timber.w("Not allowed to notify.")
|
||||||
return false
|
return false
|
||||||
|
|
@ -40,26 +40,28 @@ class DefaultNotificationDisplayer(
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelNotificationMessage(tag: String?, id: Int) {
|
override fun cancelNotification(tag: String?, id: Int) {
|
||||||
notificationManager.cancel(tag, id)
|
notificationManager.cancel(tag, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun displayDiagnosticNotification(notification: Notification): Boolean {
|
override fun displayDiagnosticNotification(notification: Notification): Boolean {
|
||||||
return showNotificationMessage(
|
return showNotification(
|
||||||
tag = "DIAGNOSTIC",
|
tag = TAG_DIAGNOSTIC,
|
||||||
id = NOTIFICATION_ID_DIAGNOSTIC,
|
id = NOTIFICATION_ID_DIAGNOSTIC,
|
||||||
notification = notification
|
notification = notification
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dismissDiagnosticNotification() {
|
override fun dismissDiagnosticNotification() {
|
||||||
cancelNotificationMessage(
|
cancelNotification(
|
||||||
tag = "DIAGNOSTIC",
|
tag = TAG_DIAGNOSTIC,
|
||||||
id = NOTIFICATION_ID_DIAGNOSTIC
|
id = NOTIFICATION_ID_DIAGNOSTIC
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val TAG_DIAGNOSTIC = "DIAGNOSTIC"
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
* IDs for notifications
|
* IDs for notifications
|
||||||
* ========================================================================================== */
|
* ========================================================================================== */
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import io.element.android.features.enterprise.api.EnterpriseService
|
||||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||||
|
|
@ -22,6 +23,7 @@ import io.element.android.libraries.push.impl.notifications.model.NotifiableEven
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
|
||||||
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
|
@ -32,6 +34,7 @@ class NotificationRenderer(
|
||||||
private val notificationDisplayer: NotificationDisplayer,
|
private val notificationDisplayer: NotificationDisplayer,
|
||||||
private val notificationDataFactory: NotificationDataFactory,
|
private val notificationDataFactory: NotificationDataFactory,
|
||||||
private val enterpriseService: EnterpriseService,
|
private val enterpriseService: EnterpriseService,
|
||||||
|
private val sessionStore: SessionStore,
|
||||||
) {
|
) {
|
||||||
suspend fun render(
|
suspend fun render(
|
||||||
currentUser: MatrixUser,
|
currentUser: MatrixUser,
|
||||||
|
|
@ -41,24 +44,29 @@ class NotificationRenderer(
|
||||||
) {
|
) {
|
||||||
val color = enterpriseService.brandColorsFlow(currentUser.userId).first()?.toArgb()
|
val color = enterpriseService.brandColorsFlow(currentUser.userId).first()?.toArgb()
|
||||||
?: NotificationConfig.NOTIFICATION_ACCENT_COLOR
|
?: NotificationConfig.NOTIFICATION_ACCENT_COLOR
|
||||||
|
val numberOfAccounts = sessionStore.numberOfSessions()
|
||||||
|
val notificationAccountParams = NotificationAccountParams(
|
||||||
|
user = currentUser,
|
||||||
|
color = color,
|
||||||
|
showSessionId = numberOfAccounts > 1,
|
||||||
|
)
|
||||||
val groupedEvents = eventsToProcess.groupByType()
|
val groupedEvents = eventsToProcess.groupByType()
|
||||||
val roomNotifications = notificationDataFactory.toNotifications(groupedEvents.roomEvents, currentUser, imageLoader, color)
|
val roomNotifications = notificationDataFactory.toNotifications(groupedEvents.roomEvents, imageLoader, notificationAccountParams)
|
||||||
val invitationNotifications = notificationDataFactory.toNotifications(groupedEvents.invitationEvents, color)
|
val invitationNotifications = notificationDataFactory.toNotifications(groupedEvents.invitationEvents, notificationAccountParams)
|
||||||
val simpleNotifications = notificationDataFactory.toNotifications(groupedEvents.simpleEvents, color)
|
val simpleNotifications = notificationDataFactory.toNotifications(groupedEvents.simpleEvents, notificationAccountParams)
|
||||||
val fallbackNotifications = notificationDataFactory.toNotifications(groupedEvents.fallbackEvents, color)
|
val fallbackNotifications = notificationDataFactory.toNotifications(groupedEvents.fallbackEvents, notificationAccountParams)
|
||||||
val summaryNotification = notificationDataFactory.createSummaryNotification(
|
val summaryNotification = notificationDataFactory.createSummaryNotification(
|
||||||
currentUser = currentUser,
|
|
||||||
roomNotifications = roomNotifications,
|
roomNotifications = roomNotifications,
|
||||||
invitationNotifications = invitationNotifications,
|
invitationNotifications = invitationNotifications,
|
||||||
simpleNotifications = simpleNotifications,
|
simpleNotifications = simpleNotifications,
|
||||||
fallbackNotifications = fallbackNotifications,
|
fallbackNotifications = fallbackNotifications,
|
||||||
color = color,
|
notificationAccountParams = notificationAccountParams,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Remove summary first to avoid briefly displaying it after dismissing the last notification
|
// Remove summary first to avoid briefly displaying it after dismissing the last notification
|
||||||
if (summaryNotification == SummaryNotification.Removed) {
|
if (summaryNotification == SummaryNotification.Removed) {
|
||||||
Timber.tag(loggerTag.value).d("Removing summary notification")
|
Timber.tag(loggerTag.value).d("Removing summary notification")
|
||||||
notificationDisplayer.cancelNotificationMessage(
|
notificationDisplayer.cancelNotification(
|
||||||
tag = null,
|
tag = null,
|
||||||
id = NotificationIdProvider.getSummaryNotificationId(currentUser.userId)
|
id = NotificationIdProvider.getSummaryNotificationId(currentUser.userId)
|
||||||
)
|
)
|
||||||
|
|
@ -69,7 +77,7 @@ class NotificationRenderer(
|
||||||
roomId = notificationData.roomId,
|
roomId = notificationData.roomId,
|
||||||
threadId = notificationData.threadId
|
threadId = notificationData.threadId
|
||||||
)
|
)
|
||||||
notificationDisplayer.showNotificationMessage(
|
notificationDisplayer.showNotification(
|
||||||
tag = tag,
|
tag = tag,
|
||||||
id = NotificationIdProvider.getRoomMessagesNotificationId(currentUser.userId),
|
id = NotificationIdProvider.getRoomMessagesNotificationId(currentUser.userId),
|
||||||
notification = notificationData.notification
|
notification = notificationData.notification
|
||||||
|
|
@ -78,9 +86,9 @@ class NotificationRenderer(
|
||||||
|
|
||||||
invitationNotifications.forEach { notificationData ->
|
invitationNotifications.forEach { notificationData ->
|
||||||
if (useCompleteNotificationFormat) {
|
if (useCompleteNotificationFormat) {
|
||||||
Timber.tag(loggerTag.value).d("Updating invitation notification ${notificationData.key}")
|
Timber.tag(loggerTag.value).d("Updating invitation notification ${notificationData.tag}")
|
||||||
notificationDisplayer.showNotificationMessage(
|
notificationDisplayer.showNotification(
|
||||||
tag = notificationData.key,
|
tag = notificationData.tag,
|
||||||
id = NotificationIdProvider.getRoomInvitationNotificationId(currentUser.userId),
|
id = NotificationIdProvider.getRoomInvitationNotificationId(currentUser.userId),
|
||||||
notification = notificationData.notification
|
notification = notificationData.notification
|
||||||
)
|
)
|
||||||
|
|
@ -89,9 +97,9 @@ class NotificationRenderer(
|
||||||
|
|
||||||
simpleNotifications.forEach { notificationData ->
|
simpleNotifications.forEach { notificationData ->
|
||||||
if (useCompleteNotificationFormat) {
|
if (useCompleteNotificationFormat) {
|
||||||
Timber.tag(loggerTag.value).d("Updating simple notification ${notificationData.key}")
|
Timber.tag(loggerTag.value).d("Updating simple notification ${notificationData.tag}")
|
||||||
notificationDisplayer.showNotificationMessage(
|
notificationDisplayer.showNotification(
|
||||||
tag = notificationData.key,
|
tag = notificationData.tag,
|
||||||
id = NotificationIdProvider.getRoomEventNotificationId(currentUser.userId),
|
id = NotificationIdProvider.getRoomEventNotificationId(currentUser.userId),
|
||||||
notification = notificationData.notification
|
notification = notificationData.notification
|
||||||
)
|
)
|
||||||
|
|
@ -101,7 +109,7 @@ class NotificationRenderer(
|
||||||
// Show only the first fallback notification
|
// Show only the first fallback notification
|
||||||
if (fallbackNotifications.isNotEmpty()) {
|
if (fallbackNotifications.isNotEmpty()) {
|
||||||
Timber.tag(loggerTag.value).d("Showing fallback notification")
|
Timber.tag(loggerTag.value).d("Showing fallback notification")
|
||||||
notificationDisplayer.showNotificationMessage(
|
notificationDisplayer.showNotification(
|
||||||
tag = "FALLBACK",
|
tag = "FALLBACK",
|
||||||
id = NotificationIdProvider.getFallbackNotificationId(currentUser.userId),
|
id = NotificationIdProvider.getFallbackNotificationId(currentUser.userId),
|
||||||
notification = fallbackNotifications.first().notification
|
notification = fallbackNotifications.first().notification
|
||||||
|
|
@ -111,7 +119,7 @@ class NotificationRenderer(
|
||||||
// Update summary last to avoid briefly displaying it before other notifications
|
// Update summary last to avoid briefly displaying it before other notifications
|
||||||
if (summaryNotification is SummaryNotification.Update) {
|
if (summaryNotification is SummaryNotification.Update) {
|
||||||
Timber.tag(loggerTag.value).d("Updating summary notification")
|
Timber.tag(loggerTag.value).d("Updating summary notification")
|
||||||
notificationDisplayer.showNotificationMessage(
|
notificationDisplayer.showNotification(
|
||||||
tag = null,
|
tag = null,
|
||||||
id = NotificationIdProvider.getSummaryNotificationId(currentUser.userId),
|
id = NotificationIdProvider.getSummaryNotificationId(currentUser.userId),
|
||||||
notification = summaryNotification.notification
|
notification = summaryNotification.notification
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,14 @@ package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import coil3.ImageLoader
|
import coil3.ImageLoader
|
||||||
import dev.zacsweers.metro.AppScope
|
import dev.zacsweers.metro.AppScope
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader
|
import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader
|
||||||
import io.element.android.libraries.push.impl.R
|
import io.element.android.libraries.push.impl.R
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.isSmartReplyError
|
import io.element.android.libraries.push.impl.notifications.factories.isSmartReplyError
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||||
|
|
@ -25,13 +24,12 @@ import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
|
|
||||||
interface RoomGroupMessageCreator {
|
interface RoomGroupMessageCreator {
|
||||||
suspend fun createRoomMessage(
|
suspend fun createRoomMessage(
|
||||||
currentUser: MatrixUser,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
events: List<NotifiableMessageEvent>,
|
events: List<NotifiableMessageEvent>,
|
||||||
roomId: RoomId,
|
roomId: RoomId,
|
||||||
threadId: ThreadId?,
|
threadId: ThreadId?,
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
existingNotification: Notification?,
|
existingNotification: Notification?,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification
|
): Notification
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,13 +40,12 @@ class DefaultRoomGroupMessageCreator(
|
||||||
private val notificationCreator: NotificationCreator,
|
private val notificationCreator: NotificationCreator,
|
||||||
) : RoomGroupMessageCreator {
|
) : RoomGroupMessageCreator {
|
||||||
override suspend fun createRoomMessage(
|
override suspend fun createRoomMessage(
|
||||||
currentUser: MatrixUser,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
events: List<NotifiableMessageEvent>,
|
events: List<NotifiableMessageEvent>,
|
||||||
roomId: RoomId,
|
roomId: RoomId,
|
||||||
threadId: ThreadId?,
|
threadId: ThreadId?,
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
existingNotification: Notification?,
|
existingNotification: Notification?,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
val lastKnownRoomEvent = events.last()
|
val lastKnownRoomEvent = events.last()
|
||||||
val roomName = lastKnownRoomEvent.roomName ?: lastKnownRoomEvent.senderDisambiguatedDisplayName ?: "Room name (${roomId.value.take(8)}…)"
|
val roomName = lastKnownRoomEvent.roomName ?: lastKnownRoomEvent.senderDisambiguatedDisplayName ?: "Room name (${roomId.value.take(8)}…)"
|
||||||
|
|
@ -66,8 +63,9 @@ class DefaultRoomGroupMessageCreator(
|
||||||
val smartReplyErrors = events.filter { it.isSmartReplyError() }
|
val smartReplyErrors = events.filter { it.isSmartReplyError() }
|
||||||
val roomIsDm = !roomIsGroup
|
val roomIsDm = !roomIsGroup
|
||||||
return notificationCreator.createMessagesListNotification(
|
return notificationCreator.createMessagesListNotification(
|
||||||
|
notificationAccountParams = notificationAccountParams,
|
||||||
RoomEventGroupInfo(
|
RoomEventGroupInfo(
|
||||||
sessionId = currentUser.userId,
|
sessionId = notificationAccountParams.user.userId,
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
roomDisplayName = roomName,
|
roomDisplayName = roomName,
|
||||||
isDm = roomIsDm,
|
isDm = roomIsDm,
|
||||||
|
|
@ -80,11 +78,9 @@ class DefaultRoomGroupMessageCreator(
|
||||||
largeIcon = largeBitmap,
|
largeIcon = largeBitmap,
|
||||||
lastMessageTimestamp = lastMessageTimestamp,
|
lastMessageTimestamp = lastMessageTimestamp,
|
||||||
tickerText = tickerText,
|
tickerText = tickerText,
|
||||||
currentUser = currentUser,
|
|
||||||
existingNotification = existingNotification,
|
existingNotification = existingNotification,
|
||||||
imageLoader = imageLoader,
|
imageLoader = imageLoader,
|
||||||
events = events,
|
events = events,
|
||||||
color = color,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,22 +8,20 @@
|
||||||
package io.element.android.libraries.push.impl.notifications
|
package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import dev.zacsweers.metro.AppScope
|
import dev.zacsweers.metro.AppScope
|
||||||
import dev.zacsweers.metro.ContributesBinding
|
import dev.zacsweers.metro.ContributesBinding
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
|
||||||
import io.element.android.libraries.push.impl.R
|
import io.element.android.libraries.push.impl.R
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
|
|
||||||
interface SummaryGroupMessageCreator {
|
interface SummaryGroupMessageCreator {
|
||||||
fun createSummaryNotification(
|
fun createSummaryNotification(
|
||||||
currentUser: MatrixUser,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
roomNotifications: List<RoomNotification>,
|
roomNotifications: List<RoomNotification>,
|
||||||
invitationNotifications: List<OneShotNotification>,
|
invitationNotifications: List<OneShotNotification>,
|
||||||
simpleNotifications: List<OneShotNotification>,
|
simpleNotifications: List<OneShotNotification>,
|
||||||
fallbackNotifications: List<OneShotNotification>,
|
fallbackNotifications: List<OneShotNotification>,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification
|
): Notification
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,30 +40,25 @@ class DefaultSummaryGroupMessageCreator(
|
||||||
private val notificationCreator: NotificationCreator,
|
private val notificationCreator: NotificationCreator,
|
||||||
) : SummaryGroupMessageCreator {
|
) : SummaryGroupMessageCreator {
|
||||||
override fun createSummaryNotification(
|
override fun createSummaryNotification(
|
||||||
currentUser: MatrixUser,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
roomNotifications: List<RoomNotification>,
|
roomNotifications: List<RoomNotification>,
|
||||||
invitationNotifications: List<OneShotNotification>,
|
invitationNotifications: List<OneShotNotification>,
|
||||||
simpleNotifications: List<OneShotNotification>,
|
simpleNotifications: List<OneShotNotification>,
|
||||||
fallbackNotifications: List<OneShotNotification>,
|
fallbackNotifications: List<OneShotNotification>,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
val summaryIsNoisy = roomNotifications.any { it.shouldBing } ||
|
val summaryIsNoisy = roomNotifications.any { it.shouldBing } ||
|
||||||
invitationNotifications.any { it.isNoisy } ||
|
invitationNotifications.any { it.isNoisy } ||
|
||||||
simpleNotifications.any { it.isNoisy }
|
simpleNotifications.any { it.isNoisy }
|
||||||
|
|
||||||
val lastMessageTimestamp = roomNotifications.lastOrNull()?.latestTimestamp
|
val lastMessageTimestamp = roomNotifications.lastOrNull()?.latestTimestamp
|
||||||
?: invitationNotifications.lastOrNull()?.timestamp
|
?: invitationNotifications.lastOrNull()?.timestamp
|
||||||
?: simpleNotifications.last().timestamp
|
?: simpleNotifications.last().timestamp
|
||||||
|
val nbEvents = roomNotifications.size + invitationNotifications.size + simpleNotifications.size
|
||||||
// FIXME roomIdToEventMap.size is not correct, this is the number of rooms
|
|
||||||
val nbEvents = roomNotifications.size + simpleNotifications.size
|
|
||||||
val sumTitle = stringProvider.getQuantityString(R.plurals.notification_compat_summary_title, nbEvents, nbEvents)
|
val sumTitle = stringProvider.getQuantityString(R.plurals.notification_compat_summary_title, nbEvents, nbEvents)
|
||||||
return notificationCreator.createSummaryListNotification(
|
return notificationCreator.createSummaryListNotification(
|
||||||
currentUser,
|
notificationAccountParams = notificationAccountParams,
|
||||||
sumTitle,
|
sumTitle,
|
||||||
noisy = summaryIsNoisy,
|
noisy = summaryIsNoisy,
|
||||||
lastMessageTimestamp = lastMessageTimestamp,
|
lastMessageTimestamp = lastMessageTimestamp,
|
||||||
color = color,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.push.impl.notifications.factories
|
||||||
|
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
|
||||||
|
data class NotificationAccountParams(
|
||||||
|
val user: MatrixUser,
|
||||||
|
@ColorInt val color: Int,
|
||||||
|
val showSessionId: Boolean,
|
||||||
|
)
|
||||||
|
|
@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader
|
import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader
|
||||||
import io.element.android.libraries.push.impl.R
|
import io.element.android.libraries.push.impl.R
|
||||||
import io.element.android.libraries.push.impl.notifications.RoomEventGroupInfo
|
import io.element.android.libraries.push.impl.notifications.RoomEventGroupInfo
|
||||||
|
|
@ -47,42 +48,40 @@ interface NotificationCreator {
|
||||||
* Create a notification for a Room.
|
* Create a notification for a Room.
|
||||||
*/
|
*/
|
||||||
suspend fun createMessagesListNotification(
|
suspend fun createMessagesListNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
roomInfo: RoomEventGroupInfo,
|
roomInfo: RoomEventGroupInfo,
|
||||||
threadId: ThreadId?,
|
threadId: ThreadId?,
|
||||||
largeIcon: Bitmap?,
|
largeIcon: Bitmap?,
|
||||||
lastMessageTimestamp: Long,
|
lastMessageTimestamp: Long,
|
||||||
tickerText: String,
|
tickerText: String,
|
||||||
currentUser: MatrixUser,
|
|
||||||
existingNotification: Notification?,
|
existingNotification: Notification?,
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
events: List<NotifiableMessageEvent>,
|
events: List<NotifiableMessageEvent>,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification
|
): Notification
|
||||||
|
|
||||||
fun createRoomInvitationNotification(
|
fun createRoomInvitationNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
inviteNotifiableEvent: InviteNotifiableEvent,
|
inviteNotifiableEvent: InviteNotifiableEvent,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification
|
): Notification
|
||||||
|
|
||||||
fun createSimpleEventNotification(
|
fun createSimpleEventNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
simpleNotifiableEvent: SimpleNotifiableEvent,
|
simpleNotifiableEvent: SimpleNotifiableEvent,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification
|
): Notification
|
||||||
|
|
||||||
fun createFallbackNotification(
|
fun createFallbackNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
fallbackNotifiableEvent: FallbackNotifiableEvent,
|
fallbackNotifiableEvent: FallbackNotifiableEvent,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification
|
): Notification
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the summary notification.
|
* Create the summary notification.
|
||||||
*/
|
*/
|
||||||
fun createSummaryListNotification(
|
fun createSummaryListNotification(
|
||||||
currentUser: MatrixUser,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
compatSummary: String,
|
compatSummary: String,
|
||||||
noisy: Boolean,
|
noisy: Boolean,
|
||||||
lastMessageTimestamp: Long,
|
lastMessageTimestamp: Long,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification
|
): Notification
|
||||||
|
|
||||||
fun createDiagnosticNotification(
|
fun createDiagnosticNotification(
|
||||||
|
|
@ -118,16 +117,15 @@ class DefaultNotificationCreator(
|
||||||
* Create a notification for a Room.
|
* Create a notification for a Room.
|
||||||
*/
|
*/
|
||||||
override suspend fun createMessagesListNotification(
|
override suspend fun createMessagesListNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
roomInfo: RoomEventGroupInfo,
|
roomInfo: RoomEventGroupInfo,
|
||||||
threadId: ThreadId?,
|
threadId: ThreadId?,
|
||||||
largeIcon: Bitmap?,
|
largeIcon: Bitmap?,
|
||||||
lastMessageTimestamp: Long,
|
lastMessageTimestamp: Long,
|
||||||
tickerText: String,
|
tickerText: String,
|
||||||
currentUser: MatrixUser,
|
|
||||||
existingNotification: Notification?,
|
existingNotification: Notification?,
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
events: List<NotifiableMessageEvent>,
|
events: List<NotifiableMessageEvent>,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
// Build the pending intent for when the notification is clicked
|
// Build the pending intent for when the notification is clicked
|
||||||
val eventId = events.firstOrNull()?.eventId
|
val eventId = events.firstOrNull()?.eventId
|
||||||
|
|
@ -135,7 +133,6 @@ class DefaultNotificationCreator(
|
||||||
threadId != null -> pendingIntentFactory.createOpenThreadPendingIntent(roomInfo.sessionId, roomInfo.roomId, eventId, threadId)
|
threadId != null -> pendingIntentFactory.createOpenThreadPendingIntent(roomInfo.sessionId, roomInfo.roomId, eventId, threadId)
|
||||||
else -> pendingIntentFactory.createOpenRoomPendingIntent(roomInfo.sessionId, roomInfo.roomId, eventId)
|
else -> pendingIntentFactory.createOpenRoomPendingIntent(roomInfo.sessionId, roomInfo.roomId, eventId)
|
||||||
}
|
}
|
||||||
val smallIcon = CommonDrawables.ic_notification
|
|
||||||
val containsMissedCall = events.any { it.type == EventType.RTC_NOTIFICATION }
|
val containsMissedCall = events.any { it.type == EventType.RTC_NOTIFICATION }
|
||||||
val channelId = if (containsMissedCall) {
|
val channelId = if (containsMissedCall) {
|
||||||
notificationChannels.getChannelForIncomingCall(false)
|
notificationChannels.getChannelForIncomingCall(false)
|
||||||
|
|
@ -159,9 +156,6 @@ class DefaultNotificationCreator(
|
||||||
setShortcutId(createShortcutId(roomInfo.sessionId, roomInfo.roomId))
|
setShortcutId(createShortcutId(roomInfo.sessionId, roomInfo.roomId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Auto-bundling is enabled for 4 or more notifications on API 24+ (N+)
|
|
||||||
// devices and all Wear devices. But we want a custom grouping, so we specify the groupID
|
|
||||||
.setGroup(roomInfo.sessionId.value)
|
|
||||||
.setGroupSummary(false)
|
.setGroupSummary(false)
|
||||||
// In order to avoid notification making sound twice (due to the summary notification)
|
// In order to avoid notification making sound twice (due to the summary notification)
|
||||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
|
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
|
||||||
|
|
@ -171,8 +165,8 @@ class DefaultNotificationCreator(
|
||||||
|
|
||||||
val messagingStyle = existingNotification?.let {
|
val messagingStyle = existingNotification?.let {
|
||||||
MessagingStyle.extractMessagingStyleFromNotification(it)
|
MessagingStyle.extractMessagingStyleFromNotification(it)
|
||||||
} ?: messagingStyleFromCurrentUser(
|
} ?: createMessagingStyleFromCurrentUser(
|
||||||
user = currentUser,
|
user = notificationAccountParams.user,
|
||||||
imageLoader = imageLoader,
|
imageLoader = imageLoader,
|
||||||
roomName = roomInfo.roomDisplayName,
|
roomName = roomInfo.roomDisplayName,
|
||||||
isThread = threadId != null,
|
isThread = threadId != null,
|
||||||
|
|
@ -187,9 +181,7 @@ class DefaultNotificationCreator(
|
||||||
.setWhen(lastMessageTimestamp)
|
.setWhen(lastMessageTimestamp)
|
||||||
// MESSAGING_STYLE sets title and content for API 16 and above devices.
|
// MESSAGING_STYLE sets title and content for API 16 and above devices.
|
||||||
.setStyle(messagingStyle)
|
.setStyle(messagingStyle)
|
||||||
.setSmallIcon(smallIcon)
|
.configureWith(notificationAccountParams)
|
||||||
// Set primary color (important for Wear 2.0 Notifications).
|
|
||||||
.setColor(color)
|
|
||||||
// Sets priority for 25 and below. For 26 and above, 'priority' is deprecated for
|
// Sets priority for 25 and below. For 26 and above, 'priority' is deprecated for
|
||||||
// 'importance' which is set in the NotificationChannel. The integers representing
|
// 'importance' which is set in the NotificationChannel. The integers representing
|
||||||
// 'priority' are different from 'importance', so make sure you don't mix them.
|
// 'priority' are different from 'importance', so make sure you don't mix them.
|
||||||
|
|
@ -202,7 +194,7 @@ class DefaultNotificationCreator(
|
||||||
setSound(it)
|
setSound(it)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
setLights(color, 500, 500)
|
setLights(notificationAccountParams.color, 500, 500)
|
||||||
} else {
|
} else {
|
||||||
priority = NotificationCompat.PRIORITY_LOW
|
priority = NotificationCompat.PRIORITY_LOW
|
||||||
}
|
}
|
||||||
|
|
@ -234,19 +226,16 @@ class DefaultNotificationCreator(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createRoomInvitationNotification(
|
override fun createRoomInvitationNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
inviteNotifiableEvent: InviteNotifiableEvent,
|
inviteNotifiableEvent: InviteNotifiableEvent,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
val smallIcon = CommonDrawables.ic_notification
|
|
||||||
val channelId = notificationChannels.getChannelIdForMessage(inviteNotifiableEvent.noisy)
|
val channelId = notificationChannels.getChannelIdForMessage(inviteNotifiableEvent.noisy)
|
||||||
return NotificationCompat.Builder(context, channelId)
|
return NotificationCompat.Builder(context, channelId)
|
||||||
.setOnlyAlertOnce(true)
|
.setOnlyAlertOnce(true)
|
||||||
.setContentTitle((inviteNotifiableEvent.roomName ?: buildMeta.applicationName).annotateForDebug(5))
|
.setContentTitle((inviteNotifiableEvent.roomName ?: buildMeta.applicationName).annotateForDebug(5))
|
||||||
.setContentText(inviteNotifiableEvent.description.annotateForDebug(6))
|
.setContentText(inviteNotifiableEvent.description.annotateForDebug(6))
|
||||||
.setGroup(inviteNotifiableEvent.sessionId.value)
|
|
||||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
|
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
|
||||||
.setSmallIcon(smallIcon)
|
.configureWith(notificationAccountParams)
|
||||||
.setColor(color)
|
|
||||||
.apply {
|
.apply {
|
||||||
addAction(rejectInvitationActionFactory.create(inviteNotifiableEvent))
|
addAction(rejectInvitationActionFactory.create(inviteNotifiableEvent))
|
||||||
addAction(acceptInvitationActionFactory.create(inviteNotifiableEvent))
|
addAction(acceptInvitationActionFactory.create(inviteNotifiableEvent))
|
||||||
|
|
@ -261,7 +250,7 @@ class DefaultNotificationCreator(
|
||||||
setSound(it)
|
setSound(it)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
setLights(color, 500, 500)
|
setLights(notificationAccountParams.color, 500, 500)
|
||||||
} else {
|
} else {
|
||||||
priority = NotificationCompat.PRIORITY_LOW
|
priority = NotificationCompat.PRIORITY_LOW
|
||||||
}
|
}
|
||||||
|
|
@ -277,19 +266,16 @@ class DefaultNotificationCreator(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createSimpleEventNotification(
|
override fun createSimpleEventNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
simpleNotifiableEvent: SimpleNotifiableEvent,
|
simpleNotifiableEvent: SimpleNotifiableEvent,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
val smallIcon = CommonDrawables.ic_notification
|
|
||||||
val channelId = notificationChannels.getChannelIdForMessage(simpleNotifiableEvent.noisy)
|
val channelId = notificationChannels.getChannelIdForMessage(simpleNotifiableEvent.noisy)
|
||||||
return NotificationCompat.Builder(context, channelId)
|
return NotificationCompat.Builder(context, channelId)
|
||||||
.setOnlyAlertOnce(true)
|
.setOnlyAlertOnce(true)
|
||||||
.setContentTitle(buildMeta.applicationName.annotateForDebug(7))
|
.setContentTitle(buildMeta.applicationName.annotateForDebug(7))
|
||||||
.setContentText(simpleNotifiableEvent.description.annotateForDebug(8))
|
.setContentText(simpleNotifiableEvent.description.annotateForDebug(8))
|
||||||
.setGroup(simpleNotifiableEvent.sessionId.value)
|
|
||||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
|
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
|
||||||
.setSmallIcon(smallIcon)
|
.configureWith(notificationAccountParams)
|
||||||
.setColor(color)
|
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setContentIntent(pendingIntentFactory.createOpenRoomPendingIntent(simpleNotifiableEvent.sessionId, simpleNotifiableEvent.roomId, null))
|
.setContentIntent(pendingIntentFactory.createOpenRoomPendingIntent(simpleNotifiableEvent.sessionId, simpleNotifiableEvent.roomId, null))
|
||||||
.apply {
|
.apply {
|
||||||
|
|
@ -301,7 +287,7 @@ class DefaultNotificationCreator(
|
||||||
setSound(it)
|
setSound(it)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
setLights(color, 500, 500)
|
setLights(notificationAccountParams.color, 500, 500)
|
||||||
} else {
|
} else {
|
||||||
priority = NotificationCompat.PRIORITY_LOW
|
priority = NotificationCompat.PRIORITY_LOW
|
||||||
}
|
}
|
||||||
|
|
@ -310,19 +296,16 @@ class DefaultNotificationCreator(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createFallbackNotification(
|
override fun createFallbackNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
fallbackNotifiableEvent: FallbackNotifiableEvent,
|
fallbackNotifiableEvent: FallbackNotifiableEvent,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
val smallIcon = CommonDrawables.ic_notification
|
|
||||||
val channelId = notificationChannels.getChannelIdForMessage(false)
|
val channelId = notificationChannels.getChannelIdForMessage(false)
|
||||||
return NotificationCompat.Builder(context, channelId)
|
return NotificationCompat.Builder(context, channelId)
|
||||||
.setOnlyAlertOnce(true)
|
.setOnlyAlertOnce(true)
|
||||||
.setContentTitle(buildMeta.applicationName.annotateForDebug(7))
|
.setContentTitle(buildMeta.applicationName.annotateForDebug(7))
|
||||||
.setContentText(fallbackNotifiableEvent.description.orEmpty().annotateForDebug(8))
|
.setContentText(fallbackNotifiableEvent.description.orEmpty().annotateForDebug(8))
|
||||||
.setGroup(fallbackNotifiableEvent.sessionId.value)
|
|
||||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
|
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_ALL)
|
||||||
.setSmallIcon(smallIcon)
|
.configureWith(notificationAccountParams)
|
||||||
.setColor(color)
|
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setWhen(fallbackNotifiableEvent.timestamp)
|
.setWhen(fallbackNotifiableEvent.timestamp)
|
||||||
// Ideally we'd use `createOpenRoomPendingIntent` here, but the broken notification might apply to an invite
|
// Ideally we'd use `createOpenRoomPendingIntent` here, but the broken notification might apply to an invite
|
||||||
|
|
@ -343,24 +326,21 @@ class DefaultNotificationCreator(
|
||||||
* Create the summary notification.
|
* Create the summary notification.
|
||||||
*/
|
*/
|
||||||
override fun createSummaryListNotification(
|
override fun createSummaryListNotification(
|
||||||
currentUser: MatrixUser,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
compatSummary: String,
|
compatSummary: String,
|
||||||
noisy: Boolean,
|
noisy: Boolean,
|
||||||
lastMessageTimestamp: Long,
|
lastMessageTimestamp: Long,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
val smallIcon = CommonDrawables.ic_notification
|
|
||||||
val channelId = notificationChannels.getChannelIdForMessage(noisy)
|
val channelId = notificationChannels.getChannelIdForMessage(noisy)
|
||||||
|
val userId = notificationAccountParams.user.userId
|
||||||
return NotificationCompat.Builder(context, channelId)
|
return NotificationCompat.Builder(context, channelId)
|
||||||
.setOnlyAlertOnce(true)
|
.setOnlyAlertOnce(true)
|
||||||
// used in compat < N, after summary is built based on child notifications
|
// used in compat < N, after summary is built based on child notifications
|
||||||
.setWhen(lastMessageTimestamp)
|
.setWhen(lastMessageTimestamp)
|
||||||
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
|
||||||
.setSmallIcon(smallIcon)
|
|
||||||
.setGroup(currentUser.userId.value)
|
|
||||||
// set this notification as the summary for the group
|
// set this notification as the summary for the group
|
||||||
.setGroupSummary(true)
|
.setGroupSummary(true)
|
||||||
.setColor(color)
|
.configureWith(notificationAccountParams)
|
||||||
.apply {
|
.apply {
|
||||||
if (noisy) {
|
if (noisy) {
|
||||||
// Compat
|
// Compat
|
||||||
|
|
@ -370,14 +350,14 @@ class DefaultNotificationCreator(
|
||||||
setSound(it)
|
setSound(it)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
setLights(color, 500, 500)
|
setLights(notificationAccountParams.color, 500, 500)
|
||||||
} else {
|
} else {
|
||||||
// compat
|
// compat
|
||||||
priority = NotificationCompat.PRIORITY_LOW
|
priority = NotificationCompat.PRIORITY_LOW
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.setContentIntent(pendingIntentFactory.createOpenSessionPendingIntent(currentUser.userId))
|
.setContentIntent(pendingIntentFactory.createOpenSessionPendingIntent(userId))
|
||||||
.setDeleteIntent(pendingIntentFactory.createDismissSummaryPendingIntent(currentUser.userId))
|
.setDeleteIntent(pendingIntentFactory.createDismissSummaryPendingIntent(userId))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -468,7 +448,7 @@ class DefaultNotificationCreator(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun messagingStyleFromCurrentUser(
|
private suspend fun createMessagingStyleFromCurrentUser(
|
||||||
user: MatrixUser,
|
user: MatrixUser,
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
roomName: String,
|
roomName: String,
|
||||||
|
|
@ -477,7 +457,8 @@ class DefaultNotificationCreator(
|
||||||
): MessagingStyle {
|
): MessagingStyle {
|
||||||
return MessagingStyle(
|
return MessagingStyle(
|
||||||
Person.Builder()
|
Person.Builder()
|
||||||
.setName(user.displayName?.annotateForDebug(50))
|
// Note: name cannot be empty else NotificationCompat.MessagingStyle() will crash
|
||||||
|
.setName(user.getBestName().annotateForDebug(50))
|
||||||
.setIcon(bitmapLoader.getUserIcon(user.avatarUrl, imageLoader))
|
.setIcon(bitmapLoader.getUserIcon(user.avatarUrl, imageLoader))
|
||||||
.setKey(user.userId.value)
|
.setKey(user.userId.value)
|
||||||
.build()
|
.build()
|
||||||
|
|
@ -497,4 +478,13 @@ class DefaultNotificationCreator(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun NotificationCompat.Builder.configureWith(notificationAccountParams: NotificationAccountParams) = apply {
|
||||||
|
setSmallIcon(CommonDrawables.ic_notification)
|
||||||
|
setColor(notificationAccountParams.color)
|
||||||
|
setGroup(notificationAccountParams.user.userId.value)
|
||||||
|
if (notificationAccountParams.showSessionId) {
|
||||||
|
setSubText(notificationAccountParams.user.userId.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun NotifiableMessageEvent.isSmartReplyError() = outGoingMessage && outGoingMessageFailed
|
fun NotifiableMessageEvent.isSmartReplyError() = outGoingMessage && outGoingMessageFailed
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class DefaultOnRedactedEventReceived(
|
||||||
oldMessage.person
|
oldMessage.person
|
||||||
)
|
)
|
||||||
messagingStyle.messages[messageToRedactIndex] = newMessage
|
messagingStyle.messages[messageToRedactIndex] = newMessage
|
||||||
notificationDisplayer.showNotificationMessage(
|
notificationDisplayer.showNotification(
|
||||||
statusBarNotification.tag,
|
statusBarNotification.tag,
|
||||||
statusBarNotification.id,
|
statusBarNotification.id,
|
||||||
NotificationCompat.Builder(context, notification)
|
NotificationCompat.Builder(context, notification)
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,17 @@ import androidx.core.app.NotificationCompat
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.appconfig.NotificationConfig
|
import io.element.android.appconfig.NotificationConfig
|
||||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
import io.element.android.libraries.matrix.test.A_COLOR_INT
|
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_TIMESTAMP
|
import io.element.android.libraries.matrix.test.A_TIMESTAMP
|
||||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.media.AVATAR_THUMBNAIL_SIZE_IN_PIXEL
|
import io.element.android.libraries.matrix.ui.media.AVATAR_THUMBNAIL_SIZE_IN_PIXEL
|
||||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||||
|
import io.element.android.libraries.matrix.ui.test.media.FakeImageLoader
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.MARK_AS_READ_ACTION_TITLE
|
import io.element.android.libraries.push.impl.notifications.factories.MARK_AS_READ_ACTION_TITLE
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.QUICK_REPLY_ACTION_TITLE
|
import io.element.android.libraries.push.impl.notifications.factories.QUICK_REPLY_ACTION_TITLE
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.aNotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.createNotificationCreator
|
import io.element.android.libraries.push.impl.notifications.factories.createNotificationCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||||
import io.element.android.libraries.push.test.notifications.FakeImageLoader
|
|
||||||
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
|
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
|
||||||
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
|
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
|
||||||
import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider
|
import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider
|
||||||
|
|
@ -44,23 +44,22 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
val fakeImageLoader = FakeImageLoader()
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
||||||
imageUriString = "aUri",
|
imageUriString = "aUri",
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
imageLoader = fakeImageLoader.getImageLoader(),
|
imageLoader = fakeImageLoader,
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
assertThat(result.number).isEqualTo(1)
|
assertThat(result.number).isEqualTo(1)
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
assertThat(result.priority).isEqualTo(NotificationCompat.PRIORITY_LOW)
|
assertThat(result.priority).isEqualTo(NotificationCompat.PRIORITY_LOW)
|
||||||
assertThat(result.`when`).isEqualTo(A_TIMESTAMP)
|
assertThat(result.`when`).isEqualTo(A_TIMESTAMP)
|
||||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
assertThat(fakeImageLoader.getExecutedRequestsData()).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -68,21 +67,20 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
val fakeImageLoader = FakeImageLoader()
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
||||||
noisy = true,
|
noisy = true,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
imageLoader = fakeImageLoader.getImageLoader(),
|
imageLoader = fakeImageLoader,
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
assertThat(result.priority).isEqualTo(NotificationCompat.PRIORITY_DEFAULT)
|
assertThat(result.priority).isEqualTo(NotificationCompat.PRIORITY_DEFAULT)
|
||||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
assertThat(fakeImageLoader.getExecutedRequestsData()).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -130,9 +128,11 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
sdkIntProvider = FakeBuildVersionSdkIntProvider(api)
|
sdkIntProvider = FakeBuildVersionSdkIntProvider(api)
|
||||||
)
|
)
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(
|
notificationAccountParams = aNotificationAccountParams(
|
||||||
// Some user avatar
|
user = aMatrixUser(
|
||||||
avatarUrl = A_USER_AVATAR_1,
|
// Some user avatar
|
||||||
|
avatarUrl = A_USER_AVATAR_1,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
||||||
|
|
@ -141,13 +141,12 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
imageLoader = fakeImageLoader.getImageLoader(),
|
imageLoader = fakeImageLoader,
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
assertThat(result.number).isEqualTo(1)
|
assertThat(result.number).isEqualTo(1)
|
||||||
assertThat(fakeImageLoader.getCoilRequests()).containsExactlyElementsIn(expectedCoilRequests)
|
assertThat(fakeImageLoader.getExecutedRequestsData()).containsExactlyElementsIn(expectedCoilRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -155,16 +154,15 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
val fakeImageLoader = FakeImageLoader()
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
aNotifiableMessageEvent(timestamp = A_TIMESTAMP),
|
aNotifiableMessageEvent(timestamp = A_TIMESTAMP),
|
||||||
aNotifiableMessageEvent(timestamp = A_TIMESTAMP + 10),
|
aNotifiableMessageEvent(timestamp = A_TIMESTAMP + 10),
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
imageLoader = fakeImageLoader.getImageLoader(),
|
imageLoader = fakeImageLoader,
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
assertThat(result.number).isEqualTo(2)
|
assertThat(result.number).isEqualTo(2)
|
||||||
assertThat(result.`when`).isEqualTo(A_TIMESTAMP + 10)
|
assertThat(result.`when`).isEqualTo(A_TIMESTAMP + 10)
|
||||||
|
|
@ -175,7 +173,7 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
QUICK_REPLY_ACTION_TITLE.takeIf { NotificationConfig.SHOW_QUICK_REPLY_ACTION },
|
QUICK_REPLY_ACTION_TITLE.takeIf { NotificationConfig.SHOW_QUICK_REPLY_ACTION },
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
assertThat(fakeImageLoader.getExecutedRequestsData()).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -183,7 +181,7 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
val fakeImageLoader = FakeImageLoader()
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
||||||
outGoingMessage = true,
|
outGoingMessage = true,
|
||||||
|
|
@ -191,10 +189,9 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
imageLoader = fakeImageLoader.getImageLoader(),
|
imageLoader = fakeImageLoader,
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
val actionTitles = result.actions?.map { it.title }
|
val actionTitles = result.actions?.map { it.title }
|
||||||
assertThat(actionTitles).isEqualTo(
|
assertThat(actionTitles).isEqualTo(
|
||||||
|
|
@ -202,7 +199,7 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
MARK_AS_READ_ACTION_TITLE.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION }
|
MARK_AS_READ_ACTION_TITLE.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
assertThat(fakeImageLoader.getExecutedRequestsData()).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -210,21 +207,20 @@ class DefaultBaseRoomGroupMessageCreatorTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
val fakeImageLoader = FakeImageLoader()
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
aNotifiableMessageEvent(timestamp = A_TIMESTAMP).copy(
|
||||||
roomIsDm = true,
|
roomIsDm = true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
imageLoader = fakeImageLoader.getImageLoader(),
|
imageLoader = fakeImageLoader,
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
assertThat(result.number).isEqualTo(1)
|
assertThat(result.number).isEqualTo(1)
|
||||||
assertThat(result.`when`).isEqualTo(A_TIMESTAMP)
|
assertThat(result.`when`).isEqualTo(A_TIMESTAMP)
|
||||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
assertThat(fakeImageLoader.getExecutedRequestsData()).isEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@
|
||||||
package io.element.android.libraries.push.impl.notifications
|
package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.compose.ui.graphics.Color
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.features.enterprise.api.EnterpriseService
|
||||||
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
||||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
|
|
@ -20,13 +20,17 @@ import io.element.android.libraries.matrix.test.A_THREAD_ID
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||||
|
import io.element.android.libraries.matrix.ui.test.media.FakeImageLoaderHolder
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.aNotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider
|
import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator
|
||||||
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||||
import io.element.android.libraries.push.test.notifications.FakeImageLoaderHolder
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
|
import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationState
|
import io.element.android.services.appnavstate.api.AppNavigationState
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
import io.element.android.services.appnavstate.api.NavigationState
|
import io.element.android.services.appnavstate.api.NavigationState
|
||||||
|
|
@ -38,25 +42,19 @@ import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.verify
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runCurrent
|
import kotlinx.coroutines.test.runCurrent
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@RunWith(RobolectricTestRunner::class)
|
|
||||||
class DefaultNotificationDrawerManagerTest {
|
class DefaultNotificationDrawerManagerTest {
|
||||||
@Test
|
@Test
|
||||||
fun `clearAllEvents should have no effect when queue is empty`() = runTest {
|
fun `clearAllEvents should have no effect when queue is empty`() = runTest {
|
||||||
val defaultNotificationDrawerManager = createDefaultNotificationDrawerManager()
|
val defaultNotificationDrawerManager = createDefaultNotificationDrawerManager()
|
||||||
defaultNotificationDrawerManager.clearAllEvents(A_SESSION_ID)
|
defaultNotificationDrawerManager.clearAllEvents(A_SESSION_ID)
|
||||||
defaultNotificationDrawerManager.destroy()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -64,8 +62,8 @@ class DefaultNotificationDrawerManagerTest {
|
||||||
// For now just call all the API. Later, add more valuable tests.
|
// For now just call all the API. Later, add more valuable tests.
|
||||||
val matrixUser = aMatrixUser(id = A_SESSION_ID.value, displayName = "alice", avatarUrl = "mxc://data")
|
val matrixUser = aMatrixUser(id = A_SESSION_ID.value, displayName = "alice", avatarUrl = "mxc://data")
|
||||||
val mockRoomGroupMessageCreator = FakeRoomGroupMessageCreator(
|
val mockRoomGroupMessageCreator = FakeRoomGroupMessageCreator(
|
||||||
createRoomMessageResult = lambdaRecorder { user, _, roomId, _, _, existingNotification ->
|
createRoomMessageResult = lambdaRecorder { notificationAccountParams, _, roomId, _, _, existingNotification ->
|
||||||
assertThat(user).isEqualTo(matrixUser)
|
assertThat(notificationAccountParams.user).isEqualTo(matrixUser)
|
||||||
assertThat(roomId).isEqualTo(A_ROOM_ID)
|
assertThat(roomId).isEqualTo(A_ROOM_ID)
|
||||||
assertThat(existingNotification).isNull()
|
assertThat(existingNotification).isNull()
|
||||||
Notification()
|
Notification()
|
||||||
|
|
@ -88,7 +86,6 @@ class DefaultNotificationDrawerManagerTest {
|
||||||
defaultNotificationDrawerManager.onNotifiableEventReceived(aNotifiableMessageEvent())
|
defaultNotificationDrawerManager.onNotifiableEventReceived(aNotifiableMessageEvent())
|
||||||
// Add the same Event again (will be ignored)
|
// Add the same Event again (will be ignored)
|
||||||
defaultNotificationDrawerManager.onNotifiableEventReceived(aNotifiableMessageEvent())
|
defaultNotificationDrawerManager.onNotifiableEventReceived(aNotifiableMessageEvent())
|
||||||
defaultNotificationDrawerManager.destroy()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -101,7 +98,7 @@ class DefaultNotificationDrawerManagerTest {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val appNavigationStateService = FakeAppNavigationStateService(appNavigationState = appNavigationStateFlow)
|
val appNavigationStateService = FakeAppNavigationStateService(appNavigationState = appNavigationStateFlow)
|
||||||
val defaultNotificationDrawerManager = createDefaultNotificationDrawerManager(
|
createDefaultNotificationDrawerManager(
|
||||||
appNavigationStateService = appNavigationStateService
|
appNavigationStateService = appNavigationStateService
|
||||||
)
|
)
|
||||||
appNavigationStateFlow.emit(AppNavigationState(aNavigationState(), isInForeground = true))
|
appNavigationStateFlow.emit(AppNavigationState(aNavigationState(), isInForeground = true))
|
||||||
|
|
@ -117,17 +114,22 @@ class DefaultNotificationDrawerManagerTest {
|
||||||
// Like a user sign out
|
// Like a user sign out
|
||||||
appNavigationStateFlow.emit(AppNavigationState(aNavigationState(), isInForeground = true))
|
appNavigationStateFlow.emit(AppNavigationState(aNavigationState(), isInForeground = true))
|
||||||
runCurrent()
|
runCurrent()
|
||||||
defaultNotificationDrawerManager.destroy()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when MatrixClient has no cached user name a fallback one is used to render the notification`() = runTest {
|
fun `when MatrixClient has no cached user name and avatar, the profile is loaded to render the notification`() = runTest {
|
||||||
val matrixClient = FakeMatrixClient(userDisplayName = null)
|
val matrixClient = FakeMatrixClient(
|
||||||
|
userDisplayName = null,
|
||||||
|
userAvatarUrl = null,
|
||||||
|
)
|
||||||
val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(matrixClient) })
|
val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(matrixClient) })
|
||||||
val messageCreator = FakeRoomGroupMessageCreator()
|
val messageCreator = FakeRoomGroupMessageCreator()
|
||||||
val defaultNotificationDrawerManager = createDefaultNotificationDrawerManager(
|
val defaultNotificationDrawerManager = createDefaultNotificationDrawerManager(
|
||||||
matrixClientProvider = matrixClientProvider,
|
matrixClientProvider = matrixClientProvider,
|
||||||
roomGroupMessageCreator = messageCreator,
|
roomGroupMessageCreator = messageCreator,
|
||||||
|
enterpriseService = FakeEnterpriseService(
|
||||||
|
initialBrandColor = Color.Red,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
// Gets a display name from MatrixClient.getUserProfile
|
// Gets a display name from MatrixClient.getUserProfile
|
||||||
matrixClient.givenGetProfileResult(A_SESSION_ID, Result.success(aMatrixUser(id = A_SESSION_ID.value, displayName = "alice")))
|
matrixClient.givenGetProfileResult(A_SESSION_ID, Result.success(aMatrixUser(id = A_SESSION_ID.value, displayName = "alice")))
|
||||||
|
|
@ -144,27 +146,41 @@ class DefaultNotificationDrawerManagerTest {
|
||||||
messageCreator.createRoomMessageResult.assertions()
|
messageCreator.createRoomMessageResult.assertions()
|
||||||
.isCalledExactly(3)
|
.isCalledExactly(3)
|
||||||
.withSequence(
|
.withSequence(
|
||||||
listOf(value(aMatrixUser(id = A_SESSION_ID.value, displayName = "alice")), any(), any(), any(), any(), any()),
|
|
||||||
listOf(value(aMatrixUser(id = A_SESSION_ID.value, displayName = A_SESSION_ID.value)), any(), any(), any(), any(), any()),
|
|
||||||
listOf(
|
listOf(
|
||||||
value(aMatrixUser(id = A_SESSION_ID.value, displayName = A_SESSION_ID.value, avatarUrl = AN_AVATAR_URL)),
|
value(aNotificationAccountParams(user = aMatrixUser(id = A_SESSION_ID.value, displayName = "alice"))),
|
||||||
|
any(),
|
||||||
|
any(),
|
||||||
|
any(),
|
||||||
|
any(),
|
||||||
|
any(),
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
value(aNotificationAccountParams(user = aMatrixUser(id = A_SESSION_ID.value, displayName = ""))),
|
||||||
|
any(),
|
||||||
|
any(),
|
||||||
|
any(),
|
||||||
|
any(),
|
||||||
|
any(),
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
value(aNotificationAccountParams(user = aMatrixUser(id = A_SESSION_ID.value, displayName = null, avatarUrl = null))),
|
||||||
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any(),
|
any(),
|
||||||
any()
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
defaultNotificationDrawerManager.destroy()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `clearSummaryNotificationIfNeeded will run after clearing all other notifications`() = runTest {
|
fun `clearSummaryNotificationIfNeeded will run after clearing all other notifications`() = runTest {
|
||||||
val notificationManager = mockk<NotificationManagerCompat> {
|
val cancelNotificationResult = lambdaRecorder<String?, Int, Unit> { _, _ -> }
|
||||||
every { cancel(any(), any()) } returns Unit
|
val notificationDisplayer = FakeNotificationDisplayer(
|
||||||
}
|
cancelNotificationResult = cancelNotificationResult,
|
||||||
|
)
|
||||||
val summaryId = NotificationIdProvider.getSummaryNotificationId(A_SESSION_ID)
|
val summaryId = NotificationIdProvider.getSummaryNotificationId(A_SESSION_ID)
|
||||||
|
val roomMessageId = NotificationIdProvider.getRoomMessagesNotificationId(A_SESSION_ID)
|
||||||
val activeNotificationsProvider = FakeActiveNotificationsProvider(
|
val activeNotificationsProvider = FakeActiveNotificationsProvider(
|
||||||
getSummaryNotificationResult = {
|
getSummaryNotificationResult = {
|
||||||
mockk {
|
mockk {
|
||||||
|
|
@ -174,7 +190,7 @@ class DefaultNotificationDrawerManagerTest {
|
||||||
countResult = { 1 },
|
countResult = { 1 },
|
||||||
)
|
)
|
||||||
val defaultNotificationDrawerManager = createDefaultNotificationDrawerManager(
|
val defaultNotificationDrawerManager = createDefaultNotificationDrawerManager(
|
||||||
notificationManager = notificationManager,
|
notificationDisplayer = notificationDisplayer,
|
||||||
activeNotificationsProvider = activeNotificationsProvider,
|
activeNotificationsProvider = activeNotificationsProvider,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -182,24 +198,26 @@ class DefaultNotificationDrawerManagerTest {
|
||||||
defaultNotificationDrawerManager.clearAllMessagesEvents(A_SESSION_ID)
|
defaultNotificationDrawerManager.clearAllMessagesEvents(A_SESSION_ID)
|
||||||
|
|
||||||
// Verify we asked to cancel the notification with summaryId
|
// Verify we asked to cancel the notification with summaryId
|
||||||
verify { notificationManager.cancel(null, summaryId) }
|
cancelNotificationResult.assertions().isCalledExactly(2).withSequence(
|
||||||
|
listOf(value(null), value(roomMessageId)),
|
||||||
defaultNotificationDrawerManager.destroy()
|
listOf(value(null), value(summaryId)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TestScope.createDefaultNotificationDrawerManager(
|
private fun TestScope.createDefaultNotificationDrawerManager(
|
||||||
notificationManager: NotificationManagerCompat = NotificationManagerCompat.from(RuntimeEnvironment.getApplication()),
|
notificationDisplayer: NotificationDisplayer = FakeNotificationDisplayer(),
|
||||||
appNavigationStateService: AppNavigationStateService = FakeAppNavigationStateService(),
|
appNavigationStateService: AppNavigationStateService = FakeAppNavigationStateService(),
|
||||||
roomGroupMessageCreator: RoomGroupMessageCreator = FakeRoomGroupMessageCreator(),
|
roomGroupMessageCreator: RoomGroupMessageCreator = FakeRoomGroupMessageCreator(),
|
||||||
summaryGroupMessageCreator: SummaryGroupMessageCreator = FakeSummaryGroupMessageCreator(),
|
summaryGroupMessageCreator: SummaryGroupMessageCreator = FakeSummaryGroupMessageCreator(),
|
||||||
activeNotificationsProvider: FakeActiveNotificationsProvider = FakeActiveNotificationsProvider(),
|
activeNotificationsProvider: FakeActiveNotificationsProvider = FakeActiveNotificationsProvider(),
|
||||||
matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(),
|
matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(),
|
||||||
|
sessionStore: SessionStore = InMemorySessionStore(),
|
||||||
|
enterpriseService: EnterpriseService = FakeEnterpriseService(),
|
||||||
): DefaultNotificationDrawerManager {
|
): DefaultNotificationDrawerManager {
|
||||||
val context = RuntimeEnvironment.getApplication()
|
|
||||||
return DefaultNotificationDrawerManager(
|
return DefaultNotificationDrawerManager(
|
||||||
notificationManager = notificationManager,
|
notificationDisplayer = notificationDisplayer,
|
||||||
notificationRenderer = NotificationRenderer(
|
notificationRenderer = NotificationRenderer(
|
||||||
notificationDisplayer = DefaultNotificationDisplayer(context, NotificationManagerCompat.from(context)),
|
notificationDisplayer = FakeNotificationDisplayer(),
|
||||||
notificationDataFactory = DefaultNotificationDataFactory(
|
notificationDataFactory = DefaultNotificationDataFactory(
|
||||||
notificationCreator = FakeNotificationCreator(),
|
notificationCreator = FakeNotificationCreator(),
|
||||||
roomGroupMessageCreator = roomGroupMessageCreator,
|
roomGroupMessageCreator = roomGroupMessageCreator,
|
||||||
|
|
@ -207,10 +225,11 @@ class DefaultNotificationDrawerManagerTest {
|
||||||
activeNotificationsProvider = activeNotificationsProvider,
|
activeNotificationsProvider = activeNotificationsProvider,
|
||||||
stringProvider = FakeStringProvider(),
|
stringProvider = FakeStringProvider(),
|
||||||
),
|
),
|
||||||
enterpriseService = FakeEnterpriseService(),
|
enterpriseService = enterpriseService,
|
||||||
|
sessionStore = sessionStore,
|
||||||
),
|
),
|
||||||
appNavigationStateService = appNavigationStateService,
|
appNavigationStateService = appNavigationStateService,
|
||||||
coroutineScope = this,
|
coroutineScope = backgroundScope,
|
||||||
matrixClientProvider = matrixClientProvider,
|
matrixClientProvider = matrixClientProvider,
|
||||||
imageLoaderHolder = FakeImageLoaderHolder(),
|
imageLoaderHolder = FakeImageLoaderHolder(),
|
||||||
activeNotificationsProvider = activeNotificationsProvider,
|
activeNotificationsProvider = activeNotificationsProvider,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
package io.element.android.libraries.push.impl.notifications
|
package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
|
|
@ -16,23 +15,19 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||||
import io.element.android.libraries.matrix.test.notification.FakeNotificationService
|
import io.element.android.libraries.matrix.test.notification.FakeNotificationService
|
||||||
import io.element.android.libraries.matrix.test.notification.aNotificationData
|
import io.element.android.libraries.matrix.test.notification.aNotificationData
|
||||||
|
import io.element.android.libraries.matrix.ui.test.media.FakeImageLoaderHolder
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider
|
import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDataFactory
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDataFactory
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||||
import io.element.android.libraries.push.test.notifications.FakeCallNotificationEventResolver
|
import io.element.android.libraries.push.test.notifications.FakeCallNotificationEventResolver
|
||||||
import io.element.android.libraries.push.test.notifications.FakeImageLoaderHolder
|
|
||||||
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
|
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.mockk.mockk
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runCurrent
|
import kotlinx.coroutines.test.runCurrent
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
|
||||||
class DefaultOnMissedCallNotificationHandlerTest {
|
class DefaultOnMissedCallNotificationHandlerTest {
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -52,11 +47,9 @@ class DefaultOnMissedCallNotificationHandlerTest {
|
||||||
val defaultOnMissedCallNotificationHandler = DefaultOnMissedCallNotificationHandler(
|
val defaultOnMissedCallNotificationHandler = DefaultOnMissedCallNotificationHandler(
|
||||||
matrixClientProvider = matrixClientProvider,
|
matrixClientProvider = matrixClientProvider,
|
||||||
defaultNotificationDrawerManager = DefaultNotificationDrawerManager(
|
defaultNotificationDrawerManager = DefaultNotificationDrawerManager(
|
||||||
notificationManager = mockk(relaxed = true),
|
notificationDisplayer = FakeNotificationDisplayer(),
|
||||||
notificationRenderer = NotificationRenderer(
|
notificationRenderer = createNotificationRenderer(
|
||||||
notificationDisplayer = FakeNotificationDisplayer(),
|
|
||||||
notificationDataFactory = dataFactory,
|
notificationDataFactory = dataFactory,
|
||||||
enterpriseService = FakeEnterpriseService(),
|
|
||||||
),
|
),
|
||||||
appNavigationStateService = FakeAppNavigationStateService(),
|
appNavigationStateService = FakeAppNavigationStateService(),
|
||||||
coroutineScope = backgroundScope,
|
coroutineScope = backgroundScope,
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,8 @@ package io.element.android.libraries.push.impl.notifications
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.libraries.matrix.test.A_COLOR_INT
|
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
import io.element.android.libraries.push.impl.notifications.factories.aNotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator
|
||||||
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||||
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
|
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
|
||||||
|
|
@ -34,7 +33,7 @@ class DefaultSummaryGroupMessageCreatorTest {
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = summaryCreator.createSummaryNotification(
|
val result = summaryCreator.createSummaryNotification(
|
||||||
currentUser = aMatrixUser(),
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
roomNotifications = listOf(
|
roomNotifications = listOf(
|
||||||
RoomNotification(
|
RoomNotification(
|
||||||
notification = Notification(),
|
notification = Notification(),
|
||||||
|
|
@ -49,12 +48,11 @@ class DefaultSummaryGroupMessageCreatorTest {
|
||||||
invitationNotifications = emptyList(),
|
invitationNotifications = emptyList(),
|
||||||
simpleNotifications = emptyList(),
|
simpleNotifications = emptyList(),
|
||||||
fallbackNotifications = emptyList(),
|
fallbackNotifications = emptyList(),
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
notificationCreator.createSummaryListNotificationResult.assertions()
|
notificationCreator.createSummaryListNotificationResult.assertions()
|
||||||
.isCalledOnce()
|
.isCalledOnce()
|
||||||
.with(any(), nonNull(), any(), any())
|
.with(any(), any(), nonNull(), any(), any())
|
||||||
|
|
||||||
// Set from the events included
|
// Set from the events included
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.A_COLOR_INT
|
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
|
import io.element.android.libraries.matrix.ui.test.media.FakeImageLoader
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.aNotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider
|
import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
||||||
|
|
@ -21,7 +22,6 @@ import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGrou
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aSimpleNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aSimpleNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent
|
||||||
import io.element.android.libraries.push.test.notifications.FakeImageLoader
|
|
||||||
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -51,16 +51,18 @@ class NotificationDataFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a room invitation when mapping to notification then it's added`() = testWith(notificationDataFactory) {
|
fun `given a room invitation when mapping to notification then it's added`() = testWith(notificationDataFactory) {
|
||||||
val expectedNotification = notificationCreator.createRoomInvitationNotificationResult(AN_INVITATION_EVENT)
|
val expectedNotification = notificationCreator.createRoomInvitationNotificationResult(
|
||||||
|
aNotificationAccountParams(),
|
||||||
|
AN_INVITATION_EVENT,
|
||||||
|
)
|
||||||
val roomInvitation = listOf(AN_INVITATION_EVENT)
|
val roomInvitation = listOf(AN_INVITATION_EVENT)
|
||||||
|
val result = toNotifications(roomInvitation, aNotificationAccountParams())
|
||||||
val result = toNotifications(roomInvitation, A_COLOR_INT)
|
|
||||||
|
|
||||||
assertThat(result).isEqualTo(
|
assertThat(result).isEqualTo(
|
||||||
listOf(
|
listOf(
|
||||||
OneShotNotification(
|
OneShotNotification(
|
||||||
notification = expectedNotification,
|
notification = expectedNotification,
|
||||||
key = A_ROOM_ID.value,
|
tag = A_ROOM_ID.value,
|
||||||
summaryLine = AN_INVITATION_EVENT.description,
|
summaryLine = AN_INVITATION_EVENT.description,
|
||||||
isNoisy = AN_INVITATION_EVENT.noisy,
|
isNoisy = AN_INVITATION_EVENT.noisy,
|
||||||
timestamp = AN_INVITATION_EVENT.timestamp
|
timestamp = AN_INVITATION_EVENT.timestamp
|
||||||
|
|
@ -71,20 +73,18 @@ class NotificationDataFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a simple event when mapping to notification then it's added`() = testWith(notificationDataFactory) {
|
fun `given a simple event when mapping to notification then it's added`() = testWith(notificationDataFactory) {
|
||||||
val expectedNotification = notificationCreator.createRoomInvitationNotificationResult(AN_INVITATION_EVENT)
|
val expectedNotification = notificationCreator.createRoomInvitationNotificationResult(
|
||||||
val roomInvitation = listOf(A_SIMPLE_EVENT)
|
aNotificationAccountParams(),
|
||||||
|
AN_INVITATION_EVENT,
|
||||||
val result = toNotifications(roomInvitation, A_COLOR_INT)
|
)
|
||||||
|
val result = toNotifications(listOf(A_SIMPLE_EVENT), aNotificationAccountParams())
|
||||||
assertThat(result).isEqualTo(
|
assertThat(result).containsExactly(
|
||||||
listOf(
|
OneShotNotification(
|
||||||
OneShotNotification(
|
notification = expectedNotification,
|
||||||
notification = expectedNotification,
|
tag = AN_EVENT_ID.value,
|
||||||
key = AN_EVENT_ID.value,
|
summaryLine = A_SIMPLE_EVENT.description,
|
||||||
summaryLine = A_SIMPLE_EVENT.description,
|
isNoisy = A_SIMPLE_EVENT.noisy,
|
||||||
isNoisy = A_SIMPLE_EVENT.noisy,
|
timestamp = AN_INVITATION_EVENT.timestamp
|
||||||
timestamp = AN_INVITATION_EVENT.timestamp
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -94,13 +94,14 @@ class NotificationDataFactoryTest {
|
||||||
val events = listOf(A_MESSAGE_EVENT)
|
val events = listOf(A_MESSAGE_EVENT)
|
||||||
val expectedNotification = RoomNotification(
|
val expectedNotification = RoomNotification(
|
||||||
notification = fakeRoomGroupMessageCreator.createRoomMessage(
|
notification = fakeRoomGroupMessageCreator.createRoomMessage(
|
||||||
currentUser = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
notificationAccountParams = aNotificationAccountParams(
|
||||||
|
user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
||||||
|
),
|
||||||
events = events,
|
events = events,
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
imageLoader = FakeImageLoader().getImageLoader(),
|
imageLoader = FakeImageLoader(),
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
color = A_COLOR_INT,
|
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
summaryLine = "A room name: Bob Hello world!",
|
summaryLine = "A room name: Bob Hello world!",
|
||||||
|
|
@ -109,35 +110,33 @@ class NotificationDataFactoryTest {
|
||||||
shouldBing = events.any { it.noisy },
|
shouldBing = events.any { it.noisy },
|
||||||
threadId = null,
|
threadId = null,
|
||||||
)
|
)
|
||||||
val roomWithMessage = listOf(A_MESSAGE_EVENT)
|
|
||||||
|
|
||||||
val fakeImageLoader = FakeImageLoader()
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = toNotifications(
|
val result = toNotifications(
|
||||||
messages = roomWithMessage,
|
messages = listOf(A_MESSAGE_EVENT),
|
||||||
currentUser = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
notificationAccountParams = aNotificationAccountParams(
|
||||||
imageLoader = fakeImageLoader.getImageLoader(),
|
user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
||||||
color = A_COLOR_INT,
|
),
|
||||||
|
imageLoader = fakeImageLoader,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(result.size).isEqualTo(1)
|
assertThat(result.size).isEqualTo(1)
|
||||||
assertThat(result.first().isDataEqualTo(expectedNotification)).isTrue()
|
assertThat(result.first().isDataEqualTo(expectedNotification)).isTrue()
|
||||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
assertThat(fakeImageLoader.getExecutedRequestsData()).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a room with only redacted events when mapping to notification then is Empty`() = testWith(notificationDataFactory) {
|
fun `given a room with only redacted events when mapping to notification then is Empty`() = testWith(notificationDataFactory) {
|
||||||
val redactedRoom = listOf(A_MESSAGE_EVENT.copy(isRedacted = true))
|
val redactedRoom = A_MESSAGE_EVENT.copy(isRedacted = true)
|
||||||
|
|
||||||
val fakeImageLoader = FakeImageLoader()
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = toNotifications(
|
val result = toNotifications(
|
||||||
messages = redactedRoom,
|
messages = listOf(redactedRoom),
|
||||||
currentUser = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
notificationAccountParams = aNotificationAccountParams(
|
||||||
imageLoader = fakeImageLoader.getImageLoader(),
|
user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
||||||
color = A_COLOR_INT,
|
),
|
||||||
|
imageLoader = fakeImageLoader,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(result).isEmpty()
|
assertThat(result).isEmpty()
|
||||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
assertThat(fakeImageLoader.getExecutedRequestsData()).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -151,13 +150,14 @@ class NotificationDataFactoryTest {
|
||||||
val withRedactedRemoved = listOf(A_MESSAGE_EVENT.copy(eventId = EventId("\$not-redacted")))
|
val withRedactedRemoved = listOf(A_MESSAGE_EVENT.copy(eventId = EventId("\$not-redacted")))
|
||||||
val expectedNotification = RoomNotification(
|
val expectedNotification = RoomNotification(
|
||||||
notification = fakeRoomGroupMessageCreator.createRoomMessage(
|
notification = fakeRoomGroupMessageCreator.createRoomMessage(
|
||||||
currentUser = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
notificationAccountParams = aNotificationAccountParams(
|
||||||
|
user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
||||||
|
),
|
||||||
events = withRedactedRemoved,
|
events = withRedactedRemoved,
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
imageLoader = FakeImageLoader().getImageLoader(),
|
imageLoader = FakeImageLoader(),
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
color = A_COLOR_INT,
|
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
summaryLine = "A room name: Bob Hello world!",
|
summaryLine = "A room name: Bob Hello world!",
|
||||||
|
|
@ -170,14 +170,15 @@ class NotificationDataFactoryTest {
|
||||||
val fakeImageLoader = FakeImageLoader()
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = toNotifications(
|
val result = toNotifications(
|
||||||
messages = roomWithRedactedMessage,
|
messages = roomWithRedactedMessage,
|
||||||
currentUser = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
notificationAccountParams = aNotificationAccountParams(
|
||||||
imageLoader = fakeImageLoader.getImageLoader(),
|
user = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
||||||
color = A_COLOR_INT,
|
),
|
||||||
|
imageLoader = fakeImageLoader,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(result.size).isEqualTo(1)
|
assertThat(result.size).isEqualTo(1)
|
||||||
assertThat(result.first().isDataEqualTo(expectedNotification)).isTrue()
|
assertThat(result.first().isDataEqualTo(expectedNotification)).isTrue()
|
||||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
assertThat(fakeImageLoader.getExecutedRequestsData()).isEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,17 @@
|
||||||
|
|
||||||
package io.element.android.libraries.push.impl.notifications
|
package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
|
import io.element.android.features.enterprise.api.EnterpriseService
|
||||||
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
|
import io.element.android.libraries.matrix.ui.test.media.FakeImageLoader
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider
|
import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator
|
||||||
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDataFactory
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator
|
||||||
|
|
@ -23,7 +26,8 @@ import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiable
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aSimpleNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aSimpleNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||||
import io.element.android.libraries.push.test.notifications.FakeImageLoader
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
|
import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
|
||||||
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
|
|
@ -38,7 +42,7 @@ private const val USE_COMPLETE_NOTIFICATION_FORMAT = true
|
||||||
|
|
||||||
private val A_SUMMARY_NOTIFICATION = SummaryNotification.Update(A_NOTIFICATION)
|
private val A_SUMMARY_NOTIFICATION = SummaryNotification.Update(A_NOTIFICATION)
|
||||||
private val ONE_SHOT_NOTIFICATION =
|
private val ONE_SHOT_NOTIFICATION =
|
||||||
OneShotNotification(notification = A_NOTIFICATION, key = "ignored", summaryLine = "ignored", isNoisy = false, timestamp = -1)
|
OneShotNotification(notification = A_NOTIFICATION, tag = "ignored", summaryLine = "ignored", isNoisy = false, timestamp = -1)
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
class NotificationRendererTest {
|
class NotificationRendererTest {
|
||||||
|
|
@ -56,10 +60,9 @@ class NotificationRendererTest {
|
||||||
)
|
)
|
||||||
private val notificationIdProvider = NotificationIdProvider
|
private val notificationIdProvider = NotificationIdProvider
|
||||||
|
|
||||||
private val notificationRenderer = NotificationRenderer(
|
private val notificationRenderer = createNotificationRenderer(
|
||||||
notificationDisplayer = notificationDisplayer,
|
notificationDisplayer = notificationDisplayer,
|
||||||
notificationDataFactory = notificationDataFactory,
|
notificationDataFactory = notificationDataFactory,
|
||||||
enterpriseService = FakeEnterpriseService(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -75,7 +78,7 @@ class NotificationRendererTest {
|
||||||
|
|
||||||
renderEventsAsNotifications(listOf(aNotifiableMessageEvent()))
|
renderEventsAsNotifications(listOf(aNotifiableMessageEvent()))
|
||||||
|
|
||||||
notificationDisplayer.showNotificationMessageResult.assertions().isCalledExactly(2).withSequence(
|
notificationDisplayer.showNotificationResult.assertions().isCalledExactly(2).withSequence(
|
||||||
listOf(value(A_ROOM_ID.value), value(notificationIdProvider.getRoomMessagesNotificationId(A_SESSION_ID)), value(A_NOTIFICATION)),
|
listOf(value(A_ROOM_ID.value), value(notificationIdProvider.getRoomMessagesNotificationId(A_SESSION_ID)), value(A_NOTIFICATION)),
|
||||||
listOf(value(null), value(notificationIdProvider.getSummaryNotificationId(A_SESSION_ID)), value(A_SUMMARY_NOTIFICATION.notification))
|
listOf(value(null), value(notificationIdProvider.getSummaryNotificationId(A_SESSION_ID)), value(A_SUMMARY_NOTIFICATION.notification))
|
||||||
)
|
)
|
||||||
|
|
@ -83,11 +86,11 @@ class NotificationRendererTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a simple notification is added when rendering then show the simple notification and update summary`() = runTest {
|
fun `given a simple notification is added when rendering then show the simple notification and update summary`() = runTest {
|
||||||
notificationCreator.createSimpleNotificationResult = lambdaRecorder { _ -> ONE_SHOT_NOTIFICATION.copy(key = AN_EVENT_ID.value).notification }
|
notificationCreator.createSimpleNotificationResult = lambdaRecorder { _, _ -> ONE_SHOT_NOTIFICATION.copy(tag = AN_EVENT_ID.value).notification }
|
||||||
|
|
||||||
renderEventsAsNotifications(listOf(aSimpleNotifiableEvent(eventId = AN_EVENT_ID)))
|
renderEventsAsNotifications(listOf(aSimpleNotifiableEvent(eventId = AN_EVENT_ID)))
|
||||||
|
|
||||||
notificationDisplayer.showNotificationMessageResult.assertions().isCalledExactly(2).withSequence(
|
notificationDisplayer.showNotificationResult.assertions().isCalledExactly(2).withSequence(
|
||||||
listOf(value(AN_EVENT_ID.value), value(notificationIdProvider.getRoomEventNotificationId(A_SESSION_ID)), value(A_NOTIFICATION)),
|
listOf(value(AN_EVENT_ID.value), value(notificationIdProvider.getRoomEventNotificationId(A_SESSION_ID)), value(A_NOTIFICATION)),
|
||||||
listOf(value(null), value(notificationIdProvider.getSummaryNotificationId(A_SESSION_ID)), value(A_SUMMARY_NOTIFICATION.notification))
|
listOf(value(null), value(notificationIdProvider.getSummaryNotificationId(A_SESSION_ID)), value(A_SUMMARY_NOTIFICATION.notification))
|
||||||
)
|
)
|
||||||
|
|
@ -95,11 +98,11 @@ class NotificationRendererTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given an invitation notification is added when rendering then show the invitation notification and update summary`() = runTest {
|
fun `given an invitation notification is added when rendering then show the invitation notification and update summary`() = runTest {
|
||||||
notificationCreator.createRoomInvitationNotificationResult = lambdaRecorder { _ -> ONE_SHOT_NOTIFICATION.copy(key = AN_EVENT_ID.value).notification }
|
notificationCreator.createRoomInvitationNotificationResult = lambdaRecorder { _, _ -> ONE_SHOT_NOTIFICATION.copy(tag = AN_EVENT_ID.value).notification }
|
||||||
|
|
||||||
renderEventsAsNotifications(listOf(anInviteNotifiableEvent()))
|
renderEventsAsNotifications(listOf(anInviteNotifiableEvent()))
|
||||||
|
|
||||||
notificationDisplayer.showNotificationMessageResult.assertions().isCalledExactly(2).withSequence(
|
notificationDisplayer.showNotificationResult.assertions().isCalledExactly(2).withSequence(
|
||||||
listOf(value(A_ROOM_ID.value), value(notificationIdProvider.getRoomInvitationNotificationId(A_SESSION_ID)), value(A_NOTIFICATION)),
|
listOf(value(A_ROOM_ID.value), value(notificationIdProvider.getRoomInvitationNotificationId(A_SESSION_ID)), value(A_NOTIFICATION)),
|
||||||
listOf(value(null), value(notificationIdProvider.getSummaryNotificationId(A_SESSION_ID)), value(A_SUMMARY_NOTIFICATION.notification))
|
listOf(value(null), value(notificationIdProvider.getSummaryNotificationId(A_SESSION_ID)), value(A_SUMMARY_NOTIFICATION.notification))
|
||||||
)
|
)
|
||||||
|
|
@ -110,7 +113,19 @@ class NotificationRendererTest {
|
||||||
MatrixUser(A_SESSION_ID, MY_USER_DISPLAY_NAME, MY_USER_AVATAR_URL),
|
MatrixUser(A_SESSION_ID, MY_USER_DISPLAY_NAME, MY_USER_AVATAR_URL),
|
||||||
useCompleteNotificationFormat = USE_COMPLETE_NOTIFICATION_FORMAT,
|
useCompleteNotificationFormat = USE_COMPLETE_NOTIFICATION_FORMAT,
|
||||||
eventsToProcess = events,
|
eventsToProcess = events,
|
||||||
imageLoader = FakeImageLoader().getImageLoader(),
|
imageLoader = FakeImageLoader(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createNotificationRenderer(
|
||||||
|
notificationDisplayer: NotificationDisplayer = FakeNotificationDisplayer(),
|
||||||
|
notificationDataFactory: NotificationDataFactory = FakeNotificationDataFactory(),
|
||||||
|
enterpriseService: EnterpriseService = FakeEnterpriseService(),
|
||||||
|
sessionStore: SessionStore = InMemorySessionStore(),
|
||||||
|
) = NotificationRenderer(
|
||||||
|
notificationDisplayer = notificationDisplayer,
|
||||||
|
notificationDataFactory = notificationDataFactory,
|
||||||
|
enterpriseService = enterpriseService,
|
||||||
|
sessionStore = sessionStore,
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID_2
|
import io.element.android.libraries.matrix.test.A_SESSION_ID_2
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||||
|
import io.element.android.libraries.matrix.ui.test.media.FakeImageLoaderHolder
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.FakeIntentProvider
|
import io.element.android.libraries.push.impl.notifications.factories.FakeIntentProvider
|
||||||
import io.element.android.libraries.push.impl.notifications.shortcut.createShortcutId
|
import io.element.android.libraries.push.impl.notifications.shortcut.createShortcutId
|
||||||
import io.element.android.libraries.push.test.notifications.FakeImageLoaderHolder
|
|
||||||
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
||||||
import io.element.android.libraries.sessionstorage.test.observer.FakeSessionObserver
|
import io.element.android.libraries.sessionstorage.test.observer.FakeSessionObserver
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.A_THREAD_ID
|
import io.element.android.libraries.matrix.test.A_THREAD_ID
|
||||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||||
|
import io.element.android.libraries.matrix.ui.test.media.FakeImageLoader
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader
|
import io.element.android.libraries.push.api.notifications.NotificationBitmapLoader
|
||||||
import io.element.android.libraries.push.impl.notifications.DefaultNotificationBitmapLoader
|
import io.element.android.libraries.push.impl.notifications.DefaultNotificationBitmapLoader
|
||||||
import io.element.android.libraries.push.impl.notifications.NotificationActionIds
|
import io.element.android.libraries.push.impl.notifications.NotificationActionIds
|
||||||
|
|
@ -36,7 +37,6 @@ import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiable
|
||||||
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
|
||||||
import io.element.android.libraries.push.test.notifications.FakeImageLoader
|
|
||||||
import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider
|
import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider
|
||||||
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||||
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
|
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
|
||||||
|
|
@ -65,6 +65,7 @@ class DefaultNotificationCreatorTest {
|
||||||
fun `test createFallbackNotification`() {
|
fun `test createFallbackNotification`() {
|
||||||
val sut = createNotificationCreator()
|
val sut = createNotificationCreator()
|
||||||
val result = sut.createFallbackNotification(
|
val result = sut.createFallbackNotification(
|
||||||
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
FallbackNotifiableEvent(
|
FallbackNotifiableEvent(
|
||||||
sessionId = A_SESSION_ID,
|
sessionId = A_SESSION_ID,
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
|
@ -77,7 +78,6 @@ class DefaultNotificationCreatorTest {
|
||||||
timestamp = A_FAKE_TIMESTAMP,
|
timestamp = A_FAKE_TIMESTAMP,
|
||||||
cause = null,
|
cause = null,
|
||||||
),
|
),
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
result.commonAssertions(
|
result.commonAssertions(
|
||||||
expectedCategory = null,
|
expectedCategory = null,
|
||||||
|
|
@ -88,6 +88,7 @@ class DefaultNotificationCreatorTest {
|
||||||
fun `test createSimpleEventNotification`() {
|
fun `test createSimpleEventNotification`() {
|
||||||
val sut = createNotificationCreator()
|
val sut = createNotificationCreator()
|
||||||
val result = sut.createSimpleEventNotification(
|
val result = sut.createSimpleEventNotification(
|
||||||
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
SimpleNotifiableEvent(
|
SimpleNotifiableEvent(
|
||||||
sessionId = A_SESSION_ID,
|
sessionId = A_SESSION_ID,
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
|
@ -103,7 +104,6 @@ class DefaultNotificationCreatorTest {
|
||||||
isRedacted = false,
|
isRedacted = false,
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
),
|
),
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
result.commonAssertions(
|
result.commonAssertions(
|
||||||
expectedCategory = null,
|
expectedCategory = null,
|
||||||
|
|
@ -114,6 +114,7 @@ class DefaultNotificationCreatorTest {
|
||||||
fun `test createSimpleEventNotification noisy`() {
|
fun `test createSimpleEventNotification noisy`() {
|
||||||
val sut = createNotificationCreator()
|
val sut = createNotificationCreator()
|
||||||
val result = sut.createSimpleEventNotification(
|
val result = sut.createSimpleEventNotification(
|
||||||
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
SimpleNotifiableEvent(
|
SimpleNotifiableEvent(
|
||||||
sessionId = A_SESSION_ID,
|
sessionId = A_SESSION_ID,
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
|
@ -129,7 +130,6 @@ class DefaultNotificationCreatorTest {
|
||||||
isRedacted = false,
|
isRedacted = false,
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
),
|
),
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
result.commonAssertions(
|
result.commonAssertions(
|
||||||
expectedCategory = null,
|
expectedCategory = null,
|
||||||
|
|
@ -140,6 +140,7 @@ class DefaultNotificationCreatorTest {
|
||||||
fun `test createRoomInvitationNotification`() {
|
fun `test createRoomInvitationNotification`() {
|
||||||
val sut = createNotificationCreator()
|
val sut = createNotificationCreator()
|
||||||
val result = sut.createRoomInvitationNotification(
|
val result = sut.createRoomInvitationNotification(
|
||||||
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
InviteNotifiableEvent(
|
InviteNotifiableEvent(
|
||||||
sessionId = A_SESSION_ID,
|
sessionId = A_SESSION_ID,
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
|
@ -156,7 +157,6 @@ class DefaultNotificationCreatorTest {
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
roomName = "roomName",
|
roomName = "roomName",
|
||||||
),
|
),
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
result.commonAssertions(
|
result.commonAssertions(
|
||||||
expectedCategory = null,
|
expectedCategory = null,
|
||||||
|
|
@ -174,6 +174,7 @@ class DefaultNotificationCreatorTest {
|
||||||
fun `test createRoomInvitationNotification noisy`() {
|
fun `test createRoomInvitationNotification noisy`() {
|
||||||
val sut = createNotificationCreator()
|
val sut = createNotificationCreator()
|
||||||
val result = sut.createRoomInvitationNotification(
|
val result = sut.createRoomInvitationNotification(
|
||||||
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
InviteNotifiableEvent(
|
InviteNotifiableEvent(
|
||||||
sessionId = A_SESSION_ID,
|
sessionId = A_SESSION_ID,
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
|
@ -190,7 +191,6 @@ class DefaultNotificationCreatorTest {
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
roomName = "roomName",
|
roomName = "roomName",
|
||||||
),
|
),
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
result.commonAssertions(
|
result.commonAssertions(
|
||||||
expectedCategory = null,
|
expectedCategory = null,
|
||||||
|
|
@ -202,11 +202,10 @@ class DefaultNotificationCreatorTest {
|
||||||
val sut = createNotificationCreator()
|
val sut = createNotificationCreator()
|
||||||
val matrixUser = aMatrixUser()
|
val matrixUser = aMatrixUser()
|
||||||
val result = sut.createSummaryListNotification(
|
val result = sut.createSummaryListNotification(
|
||||||
currentUser = matrixUser,
|
notificationAccountParams = aNotificationAccountParams(user = matrixUser),
|
||||||
compatSummary = "compatSummary",
|
compatSummary = "compatSummary",
|
||||||
noisy = false,
|
noisy = false,
|
||||||
lastMessageTimestamp = 123_456L,
|
lastMessageTimestamp = 123_456L,
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
result.commonAssertions(
|
result.commonAssertions(
|
||||||
expectedGroup = matrixUser.userId.value,
|
expectedGroup = matrixUser.userId.value,
|
||||||
|
|
@ -218,11 +217,10 @@ class DefaultNotificationCreatorTest {
|
||||||
val sut = createNotificationCreator()
|
val sut = createNotificationCreator()
|
||||||
val matrixUser = aMatrixUser()
|
val matrixUser = aMatrixUser()
|
||||||
val result = sut.createSummaryListNotification(
|
val result = sut.createSummaryListNotification(
|
||||||
currentUser = matrixUser,
|
notificationAccountParams = aNotificationAccountParams(user = matrixUser),
|
||||||
compatSummary = "compatSummary",
|
compatSummary = "compatSummary",
|
||||||
noisy = true,
|
noisy = true,
|
||||||
lastMessageTimestamp = 123_456L,
|
lastMessageTimestamp = 123_456L,
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
result.commonAssertions(
|
result.commonAssertions(
|
||||||
expectedGroup = matrixUser.userId.value,
|
expectedGroup = matrixUser.userId.value,
|
||||||
|
|
@ -232,8 +230,8 @@ class DefaultNotificationCreatorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `test createMessagesListNotification`() = runTest {
|
fun `test createMessagesListNotification`() = runTest {
|
||||||
val sut = createNotificationCreator()
|
val sut = createNotificationCreator()
|
||||||
aMatrixUser()
|
|
||||||
val result = sut.createMessagesListNotification(
|
val result = sut.createMessagesListNotification(
|
||||||
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
roomInfo = RoomEventGroupInfo(
|
roomInfo = RoomEventGroupInfo(
|
||||||
sessionId = A_SESSION_ID,
|
sessionId = A_SESSION_ID,
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
|
@ -247,11 +245,9 @@ class DefaultNotificationCreatorTest {
|
||||||
largeIcon = null,
|
largeIcon = null,
|
||||||
lastMessageTimestamp = 123_456L,
|
lastMessageTimestamp = 123_456L,
|
||||||
tickerText = "tickerText",
|
tickerText = "tickerText",
|
||||||
currentUser = aMatrixUser(),
|
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
imageLoader = FakeImageLoader().getImageLoader(),
|
imageLoader = FakeImageLoader(),
|
||||||
events = listOf(aNotifiableMessageEvent()),
|
events = listOf(aNotifiableMessageEvent()),
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
result.commonAssertions()
|
result.commonAssertions()
|
||||||
}
|
}
|
||||||
|
|
@ -259,8 +255,8 @@ class DefaultNotificationCreatorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `test createMessagesListNotification should bing and thread`() = runTest {
|
fun `test createMessagesListNotification should bing and thread`() = runTest {
|
||||||
val sut = createNotificationCreator()
|
val sut = createNotificationCreator()
|
||||||
aMatrixUser()
|
|
||||||
val result = sut.createMessagesListNotification(
|
val result = sut.createMessagesListNotification(
|
||||||
|
notificationAccountParams = aNotificationAccountParams(),
|
||||||
roomInfo = RoomEventGroupInfo(
|
roomInfo = RoomEventGroupInfo(
|
||||||
sessionId = A_SESSION_ID,
|
sessionId = A_SESSION_ID,
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
|
@ -274,17 +270,15 @@ class DefaultNotificationCreatorTest {
|
||||||
largeIcon = null,
|
largeIcon = null,
|
||||||
lastMessageTimestamp = 123_456L,
|
lastMessageTimestamp = 123_456L,
|
||||||
tickerText = "tickerText",
|
tickerText = "tickerText",
|
||||||
currentUser = aMatrixUser(),
|
|
||||||
existingNotification = null,
|
existingNotification = null,
|
||||||
imageLoader = FakeImageLoader().getImageLoader(),
|
imageLoader = FakeImageLoader(),
|
||||||
events = listOf(aNotifiableMessageEvent()),
|
events = listOf(aNotifiableMessageEvent()),
|
||||||
color = A_COLOR_INT,
|
|
||||||
)
|
)
|
||||||
result.commonAssertions()
|
result.commonAssertions()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Notification.commonAssertions(
|
private fun Notification.commonAssertions(
|
||||||
expectedGroup: String? = A_SESSION_ID.value,
|
expectedGroup: String? = aMatrixUser().userId.value,
|
||||||
expectedCategory: String? = NotificationCompat.CATEGORY_MESSAGE,
|
expectedCategory: String? = NotificationCompat.CATEGORY_MESSAGE,
|
||||||
) {
|
) {
|
||||||
assertThat(contentIntent).isNotNull()
|
assertThat(contentIntent).isNotNull()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.push.impl.notifications.factories
|
||||||
|
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
import io.element.android.libraries.matrix.test.A_COLOR_INT
|
||||||
|
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||||
|
|
||||||
|
fun aNotificationAccountParams(
|
||||||
|
user: MatrixUser = aMatrixUser(),
|
||||||
|
@ColorInt color: Int = A_COLOR_INT,
|
||||||
|
showSessionId: Boolean = false,
|
||||||
|
) = NotificationAccountParams(
|
||||||
|
user = user,
|
||||||
|
color = color,
|
||||||
|
showSessionId = showSessionId,
|
||||||
|
)
|
||||||
|
|
@ -12,81 +12,84 @@ import android.graphics.Bitmap
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import coil3.ImageLoader
|
import coil3.ImageLoader
|
||||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
|
||||||
import io.element.android.libraries.push.impl.notifications.RoomEventGroupInfo
|
import io.element.android.libraries.push.impl.notifications.RoomEventGroupInfo
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.A_NOTIFICATION
|
import io.element.android.libraries.push.impl.notifications.fixtures.A_NOTIFICATION
|
||||||
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
|
||||||
import io.element.android.tests.testutils.lambda.LambdaFourParamsRecorder
|
import io.element.android.tests.testutils.lambda.LambdaFiveParamsRecorder
|
||||||
import io.element.android.tests.testutils.lambda.LambdaListAnyParamsRecorder
|
import io.element.android.tests.testutils.lambda.LambdaListAnyParamsRecorder
|
||||||
import io.element.android.tests.testutils.lambda.LambdaNoParamRecorder
|
|
||||||
import io.element.android.tests.testutils.lambda.LambdaOneParamRecorder
|
import io.element.android.tests.testutils.lambda.LambdaOneParamRecorder
|
||||||
|
import io.element.android.tests.testutils.lambda.LambdaTwoParamsRecorder
|
||||||
import io.element.android.tests.testutils.lambda.lambdaAnyRecorder
|
import io.element.android.tests.testutils.lambda.lambdaAnyRecorder
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
|
|
||||||
class FakeNotificationCreator(
|
class FakeNotificationCreator(
|
||||||
var createMessagesListNotificationResult: LambdaListAnyParamsRecorder<Notification> = lambdaAnyRecorder { A_NOTIFICATION },
|
var createMessagesListNotificationResult: LambdaListAnyParamsRecorder<Notification> = lambdaAnyRecorder { A_NOTIFICATION },
|
||||||
var createRoomInvitationNotificationResult: LambdaOneParamRecorder<InviteNotifiableEvent, Notification> = lambdaRecorder { _ -> A_NOTIFICATION },
|
var createRoomInvitationNotificationResult: LambdaTwoParamsRecorder<NotificationAccountParams, InviteNotifiableEvent, Notification> =
|
||||||
var createSimpleNotificationResult: LambdaOneParamRecorder<SimpleNotifiableEvent, Notification> = lambdaRecorder { _ -> A_NOTIFICATION },
|
lambdaRecorder { _, _ -> A_NOTIFICATION },
|
||||||
var createFallbackNotificationResult: LambdaOneParamRecorder<FallbackNotifiableEvent, Notification> = lambdaRecorder { _ -> A_NOTIFICATION },
|
var createSimpleNotificationResult: LambdaTwoParamsRecorder<NotificationAccountParams, SimpleNotifiableEvent, Notification> =
|
||||||
var createSummaryListNotificationResult: LambdaFourParamsRecorder<MatrixUser, String, Boolean, Long, Notification> =
|
lambdaRecorder { _, _ -> A_NOTIFICATION },
|
||||||
lambdaRecorder { _, _, _, _ -> A_NOTIFICATION },
|
var createFallbackNotificationResult: LambdaTwoParamsRecorder<NotificationAccountParams, FallbackNotifiableEvent, Notification> =
|
||||||
var createDiagnosticNotificationResult: LambdaNoParamRecorder<Notification> = lambdaRecorder<Notification> { A_NOTIFICATION },
|
lambdaRecorder { _, _ -> A_NOTIFICATION },
|
||||||
|
var createSummaryListNotificationResult: LambdaFiveParamsRecorder<
|
||||||
|
NotificationAccountParams, String, Boolean, Long, NotificationAccountParams, Notification
|
||||||
|
> = lambdaRecorder { _, _, _, _, _ -> A_NOTIFICATION },
|
||||||
|
var createDiagnosticNotificationResult: LambdaOneParamRecorder<Int, Notification> =
|
||||||
|
lambdaRecorder<Int, Notification> { _ -> A_NOTIFICATION },
|
||||||
) : NotificationCreator {
|
) : NotificationCreator {
|
||||||
override suspend fun createMessagesListNotification(
|
override suspend fun createMessagesListNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
roomInfo: RoomEventGroupInfo,
|
roomInfo: RoomEventGroupInfo,
|
||||||
threadId: ThreadId?,
|
threadId: ThreadId?,
|
||||||
largeIcon: Bitmap?,
|
largeIcon: Bitmap?,
|
||||||
lastMessageTimestamp: Long,
|
lastMessageTimestamp: Long,
|
||||||
tickerText: String,
|
tickerText: String,
|
||||||
currentUser: MatrixUser,
|
|
||||||
existingNotification: Notification?,
|
existingNotification: Notification?,
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
events: List<NotifiableMessageEvent>,
|
events: List<NotifiableMessageEvent>,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
return createMessagesListNotificationResult(
|
return createMessagesListNotificationResult(
|
||||||
listOf(roomInfo, threadId, largeIcon, lastMessageTimestamp, tickerText, currentUser, existingNotification, imageLoader, events)
|
listOf(notificationAccountParams, roomInfo, threadId, largeIcon, lastMessageTimestamp, tickerText, existingNotification, imageLoader, events)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createRoomInvitationNotification(
|
override fun createRoomInvitationNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
inviteNotifiableEvent: InviteNotifiableEvent,
|
inviteNotifiableEvent: InviteNotifiableEvent,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
return createRoomInvitationNotificationResult(inviteNotifiableEvent)
|
return createRoomInvitationNotificationResult(notificationAccountParams, inviteNotifiableEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createSimpleEventNotification(
|
override fun createSimpleEventNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
simpleNotifiableEvent: SimpleNotifiableEvent,
|
simpleNotifiableEvent: SimpleNotifiableEvent,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
return createSimpleNotificationResult(simpleNotifiableEvent)
|
return createSimpleNotificationResult(notificationAccountParams, simpleNotifiableEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createFallbackNotification(
|
override fun createFallbackNotification(
|
||||||
|
notificationAccountParams: NotificationAccountParams,
|
||||||
fallbackNotifiableEvent: FallbackNotifiableEvent,
|
fallbackNotifiableEvent: FallbackNotifiableEvent,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
return createFallbackNotificationResult(fallbackNotifiableEvent)
|
return createFallbackNotificationResult(notificationAccountParams, fallbackNotifiableEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createSummaryListNotification(
|
override fun createSummaryListNotification(
|
||||||
currentUser: MatrixUser,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
compatSummary: String,
|
compatSummary: String,
|
||||||
noisy: Boolean,
|
noisy: Boolean,
|
||||||
lastMessageTimestamp: Long,
|
lastMessageTimestamp: Long,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
return createSummaryListNotificationResult(currentUser, compatSummary, noisy, lastMessageTimestamp)
|
return createSummaryListNotificationResult(notificationAccountParams, compatSummary, noisy, lastMessageTimestamp, notificationAccountParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createDiagnosticNotification(
|
override fun createDiagnosticNotification(
|
||||||
@ColorInt color: Int,
|
@ColorInt color: Int,
|
||||||
): Notification {
|
): Notification {
|
||||||
return createDiagnosticNotificationResult()
|
return createDiagnosticNotificationResult(color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,12 @@
|
||||||
|
|
||||||
package io.element.android.libraries.push.impl.notifications.fake
|
package io.element.android.libraries.push.impl.notifications.fake
|
||||||
|
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import coil3.ImageLoader
|
import coil3.ImageLoader
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
|
||||||
import io.element.android.libraries.push.impl.notifications.NotificationDataFactory
|
import io.element.android.libraries.push.impl.notifications.NotificationDataFactory
|
||||||
import io.element.android.libraries.push.impl.notifications.OneShotNotification
|
import io.element.android.libraries.push.impl.notifications.OneShotNotification
|
||||||
import io.element.android.libraries.push.impl.notifications.RoomNotification
|
import io.element.android.libraries.push.impl.notifications.RoomNotification
|
||||||
import io.element.android.libraries.push.impl.notifications.SummaryNotification
|
import io.element.android.libraries.push.impl.notifications.SummaryNotification
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.A_NOTIFICATION
|
import io.element.android.libraries.push.impl.notifications.fixtures.A_NOTIFICATION
|
||||||
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||||
|
|
@ -25,14 +24,15 @@ import io.element.android.tests.testutils.lambda.LambdaThreeParamsRecorder
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
|
|
||||||
class FakeNotificationDataFactory(
|
class FakeNotificationDataFactory(
|
||||||
var messageEventToNotificationsResult: LambdaThreeParamsRecorder<List<NotifiableMessageEvent>, MatrixUser, ImageLoader, List<RoomNotification>> =
|
var messageEventToNotificationsResult: LambdaThreeParamsRecorder<
|
||||||
lambdaRecorder { _, _, _ -> emptyList() },
|
List<NotifiableMessageEvent>, ImageLoader, NotificationAccountParams, List<RoomNotification>
|
||||||
|
> = lambdaRecorder { _, _, _ -> emptyList() },
|
||||||
var summaryToNotificationsResult: LambdaFiveParamsRecorder<
|
var summaryToNotificationsResult: LambdaFiveParamsRecorder<
|
||||||
MatrixUser,
|
|
||||||
List<RoomNotification>,
|
List<RoomNotification>,
|
||||||
List<OneShotNotification>,
|
List<OneShotNotification>,
|
||||||
List<OneShotNotification>,
|
List<OneShotNotification>,
|
||||||
List<OneShotNotification>,
|
List<OneShotNotification>,
|
||||||
|
NotificationAccountParams,
|
||||||
SummaryNotification
|
SummaryNotification
|
||||||
> = lambdaRecorder { _, _, _, _, _ -> SummaryNotification.Update(A_NOTIFICATION) },
|
> = lambdaRecorder { _, _, _, _, _ -> SummaryNotification.Update(A_NOTIFICATION) },
|
||||||
var inviteToNotificationsResult: LambdaOneParamRecorder<List<InviteNotifiableEvent>, List<OneShotNotification>> = lambdaRecorder { _ -> emptyList() },
|
var inviteToNotificationsResult: LambdaOneParamRecorder<List<InviteNotifiableEvent>, List<OneShotNotification>> = lambdaRecorder { _ -> emptyList() },
|
||||||
|
|
@ -42,18 +42,17 @@ class FakeNotificationDataFactory(
|
||||||
) : NotificationDataFactory {
|
) : NotificationDataFactory {
|
||||||
override suspend fun toNotifications(
|
override suspend fun toNotifications(
|
||||||
messages: List<NotifiableMessageEvent>,
|
messages: List<NotifiableMessageEvent>,
|
||||||
currentUser: MatrixUser,
|
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<RoomNotification> {
|
): List<RoomNotification> {
|
||||||
return messageEventToNotificationsResult(messages, currentUser, imageLoader)
|
return messageEventToNotificationsResult(messages, imageLoader, notificationAccountParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmName("toNotificationInvites")
|
@JvmName("toNotificationInvites")
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
override fun toNotifications(
|
override fun toNotifications(
|
||||||
invites: List<InviteNotifiableEvent>,
|
invites: List<InviteNotifiableEvent>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<OneShotNotification> {
|
): List<OneShotNotification> {
|
||||||
return inviteToNotificationsResult(invites)
|
return inviteToNotificationsResult(invites)
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +61,7 @@ class FakeNotificationDataFactory(
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
override fun toNotifications(
|
override fun toNotifications(
|
||||||
simpleEvents: List<SimpleNotifiableEvent>,
|
simpleEvents: List<SimpleNotifiableEvent>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<OneShotNotification> {
|
): List<OneShotNotification> {
|
||||||
return simpleEventToNotificationsResult(simpleEvents)
|
return simpleEventToNotificationsResult(simpleEvents)
|
||||||
}
|
}
|
||||||
|
|
@ -71,25 +70,24 @@ class FakeNotificationDataFactory(
|
||||||
@Suppress("INAPPLICABLE_JVM_NAME")
|
@Suppress("INAPPLICABLE_JVM_NAME")
|
||||||
override fun toNotifications(
|
override fun toNotifications(
|
||||||
fallback: List<FallbackNotifiableEvent>,
|
fallback: List<FallbackNotifiableEvent>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): List<OneShotNotification> {
|
): List<OneShotNotification> {
|
||||||
return fallbackEventToNotificationsResult(fallback)
|
return fallbackEventToNotificationsResult(fallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createSummaryNotification(
|
override fun createSummaryNotification(
|
||||||
currentUser: MatrixUser,
|
|
||||||
roomNotifications: List<RoomNotification>,
|
roomNotifications: List<RoomNotification>,
|
||||||
invitationNotifications: List<OneShotNotification>,
|
invitationNotifications: List<OneShotNotification>,
|
||||||
simpleNotifications: List<OneShotNotification>,
|
simpleNotifications: List<OneShotNotification>,
|
||||||
fallbackNotifications: List<OneShotNotification>,
|
fallbackNotifications: List<OneShotNotification>,
|
||||||
@ColorInt color: Int,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
): SummaryNotification {
|
): SummaryNotification {
|
||||||
return summaryToNotificationsResult(
|
return summaryToNotificationsResult(
|
||||||
currentUser,
|
|
||||||
roomNotifications,
|
roomNotifications,
|
||||||
invitationNotifications,
|
invitationNotifications,
|
||||||
simpleNotifications,
|
simpleNotifications,
|
||||||
fallbackNotifications,
|
fallbackNotifications,
|
||||||
|
notificationAccountParams,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,17 @@ import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
|
|
||||||
class FakeNotificationDisplayer(
|
class FakeNotificationDisplayer(
|
||||||
var showNotificationMessageResult: LambdaThreeParamsRecorder<String?, Int, Notification, Boolean> = lambdaRecorder { _, _, _ -> true },
|
var showNotificationResult: LambdaThreeParamsRecorder<String?, Int, Notification, Boolean> = lambdaRecorder { _, _, _ -> true },
|
||||||
var cancelNotificationMessageResult: LambdaTwoParamsRecorder<String?, Int, Unit> = lambdaRecorder { _, _ -> },
|
var cancelNotificationResult: LambdaTwoParamsRecorder<String?, Int, Unit> = lambdaRecorder { _, _ -> },
|
||||||
var displayDiagnosticNotificationResult: LambdaOneParamRecorder<Notification, Boolean> = lambdaRecorder { _ -> true },
|
var displayDiagnosticNotificationResult: LambdaOneParamRecorder<Notification, Boolean> = lambdaRecorder { _ -> true },
|
||||||
var dismissDiagnosticNotificationResult: LambdaNoParamRecorder<Unit> = lambdaRecorder { -> },
|
var dismissDiagnosticNotificationResult: LambdaNoParamRecorder<Unit> = lambdaRecorder { -> },
|
||||||
) : NotificationDisplayer {
|
) : NotificationDisplayer {
|
||||||
override fun showNotificationMessage(tag: String?, id: Int, notification: Notification): Boolean {
|
override fun showNotification(tag: String?, id: Int, notification: Notification): Boolean {
|
||||||
return showNotificationMessageResult(tag, id, notification)
|
return showNotificationResult(tag, id, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cancelNotificationMessage(tag: String?, id: Int) {
|
override fun cancelNotification(tag: String?, id: Int) {
|
||||||
return cancelNotificationMessageResult(tag, id)
|
return cancelNotificationResult(tag, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun displayDiagnosticNotification(notification: Notification): Boolean {
|
override fun displayDiagnosticNotification(notification: Notification): Boolean {
|
||||||
|
|
@ -41,7 +41,7 @@ class FakeNotificationDisplayer(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun verifySummaryCancelled(times: Int = 1) {
|
fun verifySummaryCancelled(times: Int = 1) {
|
||||||
cancelNotificationMessageResult.assertions().isCalledExactly(times).withSequence(
|
cancelNotificationResult.assertions().isCalledExactly(times).withSequence(
|
||||||
listOf(value(null), value(NotificationIdProvider.getSummaryNotificationId(A_SESSION_ID)))
|
listOf(value(null), value(NotificationIdProvider.getSummaryNotificationId(A_SESSION_ID)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,11 @@
|
||||||
package io.element.android.libraries.push.impl.notifications.fake
|
package io.element.android.libraries.push.impl.notifications.fake
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import coil3.ImageLoader
|
import coil3.ImageLoader
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
|
||||||
import io.element.android.libraries.push.impl.notifications.RoomGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.RoomGroupMessageCreator
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.A_NOTIFICATION
|
import io.element.android.libraries.push.impl.notifications.fixtures.A_NOTIFICATION
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||||
import io.element.android.tests.testutils.lambda.LambdaSixParamsRecorder
|
import io.element.android.tests.testutils.lambda.LambdaSixParamsRecorder
|
||||||
|
|
@ -22,18 +21,18 @@ import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
// We just can't make the param types fit
|
// We just can't make the param types fit
|
||||||
@Suppress("MaxLineLength", "ktlint:standard:max-line-length", "ktlint:standard:parameter-wrapping")
|
@Suppress("MaxLineLength", "ktlint:standard:max-line-length", "ktlint:standard:parameter-wrapping")
|
||||||
class FakeRoomGroupMessageCreator(
|
class FakeRoomGroupMessageCreator(
|
||||||
var createRoomMessageResult: LambdaSixParamsRecorder<MatrixUser, List<NotifiableMessageEvent>, RoomId, ThreadId?, ImageLoader, Notification?, Notification> =
|
var createRoomMessageResult: LambdaSixParamsRecorder<
|
||||||
lambdaRecorder { _, _, _, _, _, _ -> A_NOTIFICATION }
|
NotificationAccountParams, List<NotifiableMessageEvent>, RoomId, ThreadId?, ImageLoader, Notification?, Notification
|
||||||
|
> = lambdaRecorder { _, _, _, _, _, _ -> A_NOTIFICATION }
|
||||||
) : RoomGroupMessageCreator {
|
) : RoomGroupMessageCreator {
|
||||||
override suspend fun createRoomMessage(
|
override suspend fun createRoomMessage(
|
||||||
currentUser: MatrixUser,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
events: List<NotifiableMessageEvent>,
|
events: List<NotifiableMessageEvent>,
|
||||||
roomId: RoomId,
|
roomId: RoomId,
|
||||||
threadId: ThreadId?,
|
threadId: ThreadId?,
|
||||||
imageLoader: ImageLoader,
|
imageLoader: ImageLoader,
|
||||||
existingNotification: Notification?,
|
existingNotification: Notification?,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
return createRoomMessageResult(currentUser, events, roomId, threadId, imageLoader, existingNotification)
|
return createRoomMessageResult(notificationAccountParams, events, roomId, threadId, imageLoader, existingNotification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,30 +8,28 @@
|
||||||
package io.element.android.libraries.push.impl.notifications.fake
|
package io.element.android.libraries.push.impl.notifications.fake
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
|
||||||
import io.element.android.libraries.push.impl.notifications.OneShotNotification
|
import io.element.android.libraries.push.impl.notifications.OneShotNotification
|
||||||
import io.element.android.libraries.push.impl.notifications.RoomNotification
|
import io.element.android.libraries.push.impl.notifications.RoomNotification
|
||||||
import io.element.android.libraries.push.impl.notifications.SummaryGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.SummaryGroupMessageCreator
|
||||||
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.A_NOTIFICATION
|
import io.element.android.libraries.push.impl.notifications.fixtures.A_NOTIFICATION
|
||||||
import io.element.android.tests.testutils.lambda.LambdaFiveParamsRecorder
|
import io.element.android.tests.testutils.lambda.LambdaFiveParamsRecorder
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
|
|
||||||
class FakeSummaryGroupMessageCreator(
|
class FakeSummaryGroupMessageCreator(
|
||||||
var createSummaryNotificationResult: LambdaFiveParamsRecorder<
|
var createSummaryNotificationResult: LambdaFiveParamsRecorder<
|
||||||
MatrixUser, List<RoomNotification>, List<OneShotNotification>, List<OneShotNotification>, List<OneShotNotification>, Notification> =
|
NotificationAccountParams, List<RoomNotification>, List<OneShotNotification>, List<OneShotNotification>, List<OneShotNotification>, Notification> =
|
||||||
lambdaRecorder { _, _, _, _, _ -> A_NOTIFICATION }
|
lambdaRecorder { _, _, _, _, _ -> A_NOTIFICATION }
|
||||||
) : SummaryGroupMessageCreator {
|
) : SummaryGroupMessageCreator {
|
||||||
override fun createSummaryNotification(
|
override fun createSummaryNotification(
|
||||||
currentUser: MatrixUser,
|
notificationAccountParams: NotificationAccountParams,
|
||||||
roomNotifications: List<RoomNotification>,
|
roomNotifications: List<RoomNotification>,
|
||||||
invitationNotifications: List<OneShotNotification>,
|
invitationNotifications: List<OneShotNotification>,
|
||||||
simpleNotifications: List<OneShotNotification>,
|
simpleNotifications: List<OneShotNotification>,
|
||||||
fallbackNotifications: List<OneShotNotification>,
|
fallbackNotifications: List<OneShotNotification>,
|
||||||
@ColorInt color: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
return createSummaryNotificationResult(
|
return createSummaryNotificationResult(
|
||||||
currentUser,
|
notificationAccountParams,
|
||||||
roomNotifications,
|
roomNotifications,
|
||||||
invitationNotifications,
|
invitationNotifications,
|
||||||
simpleNotifications,
|
simpleNotifications,
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ class DefaultOnRedactedEventReceivedTest {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
displayer = FakeNotificationDisplayer(showNotificationMessageResult = showNotificationLambda),
|
displayer = FakeNotificationDisplayer(showNotificationResult = showNotificationLambda),
|
||||||
)
|
)
|
||||||
sut.onRedactedEventsReceived(listOf(ResolvedPushEvent.Redaction(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, null)))
|
sut.onRedactedEventsReceived(listOf(ResolvedPushEvent.Redaction(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, null)))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023, 2024 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
||||||
* Please see LICENSE files in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.libraries.push.test.notifications
|
|
||||||
|
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.drawable.ColorDrawable
|
|
||||||
import coil3.ImageLoader
|
|
||||||
import coil3.test.FakeImageLoaderEngine
|
|
||||||
import coil3.test.intercept
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
|
||||||
|
|
||||||
class FakeImageLoader {
|
|
||||||
private val coilRequests = mutableListOf<Any>()
|
|
||||||
|
|
||||||
private var cache: ImageLoader? = null
|
|
||||||
|
|
||||||
fun getImageLoader(): ImageLoader {
|
|
||||||
return cache ?: ImageLoader.Builder(RuntimeEnvironment.getApplication())
|
|
||||||
.components {
|
|
||||||
val engine = FakeImageLoaderEngine.Builder()
|
|
||||||
.intercept(
|
|
||||||
predicate = {
|
|
||||||
coilRequests.add(it)
|
|
||||||
true
|
|
||||||
},
|
|
||||||
drawable = ColorDrawable(Color.BLUE)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
add(engine)
|
|
||||||
}
|
|
||||||
.build()
|
|
||||||
.also {
|
|
||||||
cache = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getCoilRequests(): List<Any> {
|
|
||||||
return coilRequests.toList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue