Show basic notification when push is recieve

This commit is contained in:
Benoit Marty 2023-03-30 14:18:23 +02:00 committed by Benoit Marty
parent 1f09f5f0eb
commit afbd4672e6
10 changed files with 124 additions and 16 deletions

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.x.intent
import android.content.Context
import android.content.Intent
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.push.impl.intent.IntentProvider
import io.element.android.x.MainActivity
import javax.inject.Inject
// TODO EAx change to deep-link.
@ContributesBinding(AppScope::class)
class IntentProviderImpl @Inject constructor(
@ApplicationContext private val context: Context,
) : IntentProvider {
override fun getMainIntent(): Intent {
return Intent(context, MainActivity::class.java)
}
}

View file

@ -67,7 +67,7 @@ class PushersManager @Inject constructor(
val client = matrixAuthenticationService.restoreSession(SessionId(sessionData.userId)).getOrNull() val client = matrixAuthenticationService.restoreSession(SessionId(sessionData.userId)).getOrNull()
client ?: return@forEach client ?: return@forEach
client.pushersService().setHttpPusher(createHttpPusher(pushKey, gateway, sessionData.userId)) client.pushersService().setHttpPusher(createHttpPusher(pushKey, gateway, sessionData.userId))
// Close sessions? // TODO EAx Close sessions
} }
} }
@ -76,7 +76,7 @@ class PushersManager @Inject constructor(
// Register the pusher for the session // Register the pusher for the session
val client = matrixAuthenticationService.restoreSession(userId).getOrNull() ?: return val client = matrixAuthenticationService.restoreSession(userId).getOrNull() ?: return
client.pushersService().setHttpPusher(createHttpPusher(pushKey, PushConfig.pusher_http_url, userId.value)) client.pushersService().setHttpPusher(createHttpPusher(pushKey, PushConfig.pusher_http_url, userId.value))
// Close sessions? // TODO EAx Close sessions
} }
private suspend fun createHttpPusher( private suspend fun createHttpPusher(

View file

@ -142,9 +142,12 @@ class VectorPushHandler @Inject constructor(
eventId = pushData.eventId, eventId = pushData.eventId,
) )
// TODO Remove
Timber.w("Notification: $notificationData") Timber.w("Notification: $notificationData")
// TODO Display notification // TODO Display notification
notificationDrawerManager.displayTemporaryNotification()
/* TODO EAx /* TODO EAx
- get the event - get the event
- display the notif - display the notif

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.push.impl.intent
import android.content.Intent
interface IntentProvider {
/**
* Provide an intent to start the application
*/
fun getMainIntent(): Intent
}

View file

@ -16,20 +16,28 @@
package io.element.android.libraries.push.impl.notifications package io.element.android.libraries.push.impl.notifications
import android.Manifest
import android.app.Notification import android.app.Notification
import android.content.Context import android.content.Context
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.ApplicationContext
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class NotificationDisplayer @Inject constructor( const val TEMPORARY_ID = 101
@ApplicationContext context: Context,
) {
class NotificationDisplayer @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val notificationManager = NotificationManagerCompat.from(context) private val notificationManager = NotificationManagerCompat.from(context)
fun showNotificationMessage(tag: String?, id: Int, notification: Notification) { fun showNotificationMessage(tag: String?, id: Int, notification: Notification) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
Timber.w("Not allowed to notify.")
return
}
notificationManager.notify(tag, id, notification) notificationManager.notify(tag, id, notification)
} }

View file

@ -41,7 +41,6 @@ import javax.inject.Inject
@SingleIn(AppScope::class) @SingleIn(AppScope::class)
class NotificationDrawerManager @Inject constructor( class NotificationDrawerManager @Inject constructor(
@ApplicationContext context: Context, @ApplicationContext context: Context,
private val notificationDisplayer: NotificationDisplayer,
private val pushDataStore: PushDataStore, private val pushDataStore: PushDataStore,
// private val activeSessionDataSource: ActiveSessionDataSource, // private val activeSessionDataSource: ActiveSessionDataSource,
private val notifiableEventProcessor: NotifiableEventProcessor, private val notifiableEventProcessor: NotifiableEventProcessor,
@ -154,7 +153,7 @@ class NotificationDrawerManager @Inject constructor(
val newSettings = pushDataStore.useCompleteNotificationFormat() val newSettings = pushDataStore.useCompleteNotificationFormat()
if (newSettings != useCompleteNotificationFormat) { if (newSettings != useCompleteNotificationFormat) {
// Settings has changed, remove all current notifications // Settings has changed, remove all current notifications
notificationDisplayer.cancelAllNotifications() notificationRenderer.cancelAllNotifications()
useCompleteNotificationFormat = newSettings useCompleteNotificationFormat = newSettings
} }
} }
@ -232,6 +231,13 @@ class NotificationDrawerManager @Inject constructor(
return resolvedEvent.shouldIgnoreMessageEventInRoom(currentRoomId, currentThreadId) return resolvedEvent.shouldIgnoreMessageEventInRoom(currentRoomId, currentThreadId)
} }
/**
* Temporary notification for EAx
*/
fun displayTemporaryNotification() {
notificationRenderer.displayTemporaryNotification()
}
companion object { companion object {
const val SUMMARY_NOTIFICATION_ID = 0 const val SUMMARY_NOTIFICATION_ID = 0
const val ROOM_MESSAGES_NOTIFICATION_ID = 1 const val ROOM_MESSAGES_NOTIFICATION_ID = 1

View file

@ -105,6 +105,10 @@ class NotificationFactory @Inject constructor(
) )
} }
} }
fun createTemporaryNotification(): Notification {
return notificationUtils.createTemporaryNotification()
}
} }
sealed interface RoomNotification { sealed interface RoomNotification {

View file

@ -104,6 +104,15 @@ class NotificationRenderer @Inject constructor(
} }
} }
} }
fun cancelAllNotifications() {
notificationDisplayer.cancelAllNotifications()
}
fun displayTemporaryNotification() {
val notification = notificationFactory.createTemporaryNotification()
notificationDisplayer.showNotificationMessage(null, TEMPORARY_ID, notification)
}
} }
private fun List<ProcessedEvent<NotifiableEvent>>.groupByType(): GroupedNotificationEvents { private fun List<ProcessedEvent<NotifiableEvent>>.groupByType(): GroupedNotificationEvents {

View file

@ -45,6 +45,7 @@ import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.SingleIn import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.push.impl.R import io.element.android.libraries.push.impl.R
import io.element.android.libraries.push.impl.intent.IntentProvider
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.services.toolbox.api.strings.StringProvider import io.element.android.services.toolbox.api.strings.StringProvider
@ -61,6 +62,7 @@ class NotificationUtils @Inject constructor(
private val stringProvider: StringProvider, private val stringProvider: StringProvider,
private val clock: SystemClock, private val clock: SystemClock,
private val actionIds: NotificationActionIds, private val actionIds: NotificationActionIds,
private val intentProvider: IntentProvider,
private val buildMeta: BuildMeta, private val buildMeta: BuildMeta,
) { ) {
@ -107,6 +109,10 @@ class NotificationUtils @Inject constructor(
private val notificationManager = NotificationManagerCompat.from(context) private val notificationManager = NotificationManagerCompat.from(context)
init {
createNotificationChannels()
}
/* ========================================================================================== /* ==========================================================================================
* Channel names * Channel names
* ========================================================================================== */ * ========================================================================================== */
@ -114,7 +120,7 @@ class NotificationUtils @Inject constructor(
/** /**
* Create notification channels. * Create notification channels.
*/ */
fun createNotificationChannels() { private fun createNotificationChannels() {
if (!supportNotificationChannels()) { if (!supportNotificationChannels()) {
return return
} }
@ -650,14 +656,6 @@ class NotificationUtils @Inject constructor(
) )
} }
fun showNotificationMessage(tag: String?, id: Int, notification: Notification) {
notificationManager.notify(tag, id, notification)
}
fun cancelNotificationMessage(tag: String?, id: Int) {
notificationManager.cancel(tag, id)
}
/** /**
* Cancel the foreground notification service. * Cancel the foreground notification service.
*/ */
@ -705,6 +703,23 @@ class NotificationUtils @Inject constructor(
) )
} }
fun createTemporaryNotification(): Notification {
val contentIntent = intentProvider.getMainIntent()
val pendingIntent = PendingIntent.getActivity(context, 0, contentIntent, PendingIntentCompat.FLAG_IMMUTABLE)
return NotificationCompat.Builder(context, NOISY_NOTIFICATION_CHANNEL_ID)
.setContentTitle(buildMeta.applicationName)
.setContentText(stringProvider.getString(R.string.notification_new_messages_temporary))
.setSmallIcon(R.drawable.ic_notification)
.setLargeIcon(getBitmap(context, R.drawable.element_logo_green))
.setColor(ContextCompat.getColor(context, R.color.notification_accent_color))
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_STATUS)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.build()
}
private fun getBitmap(context: Context, @DrawableRes drawableRes: Int): Bitmap? { private fun getBitmap(context: Context, @DrawableRes drawableRes: Int): Bitmap? {
val drawable = ResourcesCompat.getDrawable(context.resources, drawableRes, null) ?: return null val drawable = ResourcesCompat.getDrawable(context.resources, drawableRes, null) ?: return null
val canvas = Canvas() val canvas = Canvas()

View file

@ -25,6 +25,7 @@
<string name="notification_silent_notifications">Silent notifications</string> <string name="notification_silent_notifications">Silent notifications</string>
<string name="call">Call</string> <string name="call">Call</string>
<string name="notification_new_messages">New Messages</string> <string name="notification_new_messages">New Messages</string>
<string name="notification_new_messages_temporary">You have new message(s)</string>
<string name="action_mark_room_read">Mark as read</string> <string name="action_mark_room_read">Mark as read</string>
<string name="action_join">Join</string> <string name="action_join">Join</string>
<string name="action_reject">Reject</string> <string name="action_reject">Reject</string>