restrict deletion of "Recording available" notification

...for preparation to replace Dialog that was openend in ChatController. It will be replaced by Notification Actions.

The dialog was not opened when already being in a chat, because remapChatController only moved the currentChatController to top so to won't be initialized again. That's why the dialog didn't pop up for this case.

As a solution, the actions should be available directly inside the notification.

For this, it must be avoided that the "recording available" notification is closed whenever the chat is opened.

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2023-02-24 12:32:27 +01:00
parent 328a747d79
commit 0f3662cd82
No known key found for this signature in database
GPG Key ID: C793F8B59F43CE7B
3 changed files with 98 additions and 32 deletions

View File

@ -85,6 +85,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MESSAGE_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MESSAGE_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_RECORDING_NOTIFICATION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_RECORDING_NOTIFICATION
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_RESTRICT_DELETION
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_TIMESTAMP import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_TIMESTAMP
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID
@ -413,44 +414,17 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
} else { } else {
pushMessage.subject = ncNotification.subject.orEmpty() pushMessage.subject = ncNotification.subject.orEmpty()
} }
if ("recording" == ncNotification.objectType) {
conversationType = "recording"
}
} }
@Suppress("MagicNumber") @Suppress("MagicNumber")
private fun showNotification(intent: Intent) { private fun showNotification(intent: Intent) {
val largeIcon: Bitmap var category = ""
val priority = NotificationCompat.PRIORITY_HIGH
val smallIcon: Int = R.drawable.ic_logo
var category: String = ""
when (pushMessage.type) { when (pushMessage.type) {
TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING -> category = Notification.CATEGORY_MESSAGE TYPE_CHAT, TYPE_ROOM, TYPE_RECORDING -> category = Notification.CATEGORY_MESSAGE
TYPE_CALL -> category = Notification.CATEGORY_CALL TYPE_CALL -> category = Notification.CATEGORY_CALL
else -> Log.e(TAG, "unknown pushMessage.type") else -> Log.e(TAG, "unknown pushMessage.type")
} }
when (conversationType) {
"recording" -> {
largeIcon = ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_videocam_24)?.toBitmap()!!
}
"one2one" -> {
pushMessage.subject = ""
largeIcon = ContextCompat.getDrawable(context!!, R.drawable.ic_people_group_black_24px)?.toBitmap()!!
}
"group" ->
largeIcon = ContextCompat.getDrawable(context!!, R.drawable.ic_people_group_black_24px)?.toBitmap()!!
"public" -> largeIcon = ContextCompat.getDrawable(context!!, R.drawable.ic_link_black_24px)?.toBitmap()!!
else -> // assuming one2one
largeIcon = if (TYPE_CHAT == pushMessage.type || TYPE_ROOM == pushMessage.type) {
ContextCompat.getDrawable(context!!, R.drawable.ic_comment)?.toBitmap()!!
} else {
ContextCompat.getDrawable(context!!, R.drawable.ic_call_black_24dp)?.toBitmap()!!
}
}
// Use unique request code to make sure that a new PendingIntent gets created for each notification // Use unique request code to make sure that a new PendingIntent gets created for each notification
// See https://github.com/nextcloud/talk-android/issues/2111 // See https://github.com/nextcloud/talk-android/issues/2111
val requestCode = System.currentTimeMillis().toInt() val requestCode = System.currentTimeMillis().toInt()
@ -474,10 +448,10 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
} }
val notificationBuilder = NotificationCompat.Builder(context!!, "1") val notificationBuilder = NotificationCompat.Builder(context!!, "1")
.setLargeIcon(largeIcon) .setPriority(NotificationCompat.PRIORITY_HIGH)
.setSmallIcon(smallIcon)
.setCategory(category) .setCategory(category)
.setPriority(priority) .setLargeIcon(getLargeIcon())
.setSmallIcon(R.drawable.ic_logo)
.setContentTitle(contentTitle) .setContentTitle(contentTitle)
.setContentText(contentText) .setContentText(contentText)
.setSubText(baseUrl) .setSubText(baseUrl)
@ -492,6 +466,11 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
// could be an ID or a TOKEN // could be an ID or a TOKEN
notificationInfoBundle.putString(KEY_ROOM_TOKEN, pushMessage.id) notificationInfoBundle.putString(KEY_ROOM_TOKEN, pushMessage.id)
notificationInfoBundle.putLong(KEY_NOTIFICATION_ID, pushMessage.notificationId!!) notificationInfoBundle.putLong(KEY_NOTIFICATION_ID, pushMessage.notificationId!!)
if (pushMessage.type == TYPE_RECORDING) {
notificationInfoBundle.putBoolean(KEY_NOTIFICATION_RESTRICT_DELETION, true)
}
notificationBuilder.setExtras(notificationInfoBundle) notificationBuilder.setExtras(notificationInfoBundle)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -530,6 +509,15 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
addMarkAsReadAction(notificationBuilder, systemNotificationId) addMarkAsReadAction(notificationBuilder, systemNotificationId)
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
TYPE_RECORDING == pushMessage.type &&
pushMessage.notificationUser != null
) {
prepareChatNotification(notificationBuilder, activeStatusBarNotification, systemNotificationId)
// addDiscardRecordingAvailableAction(notificationBuilder, systemNotificationId)
// addShareRecordingToChatAction(notificationBuilder, systemNotificationId)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
TYPE_RECORDING == pushMessage.type && TYPE_RECORDING == pushMessage.type &&
pushMessage.notificationUser != null // null pushMessage.notificationUser != null // null
@ -539,6 +527,34 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
sendNotification(systemNotificationId, notificationBuilder.build()) sendNotification(systemNotificationId, notificationBuilder.build())
} }
private fun getLargeIcon(): Bitmap {
val largeIcon: Bitmap
if (pushMessage.type == "recording") {
largeIcon = ContextCompat.getDrawable(context!!, R.drawable.ic_baseline_videocam_24)?.toBitmap()!!
} else {
when (conversationType) {
"one2one" -> {
pushMessage.subject = ""
largeIcon =
ContextCompat.getDrawable(context!!, R.drawable.ic_people_group_black_24px)?.toBitmap()!!
}
"group" ->
largeIcon =
ContextCompat.getDrawable(context!!, R.drawable.ic_people_group_black_24px)?.toBitmap()!!
"public" ->
largeIcon =
ContextCompat.getDrawable(context!!, R.drawable.ic_link_black_24px)?.toBitmap()!!
else -> // assuming one2one
largeIcon = if (TYPE_CHAT == pushMessage.type || TYPE_ROOM == pushMessage.type) {
ContextCompat.getDrawable(context!!, R.drawable.ic_comment)?.toBitmap()!!
} else {
ContextCompat.getDrawable(context!!, R.drawable.ic_call_black_24dp)?.toBitmap()!!
}
}
}
return largeIcon
}
private fun calculateCRC32(s: String): Long { private fun calculateCRC32(s: String): Long {
val crc32 = CRC32() val crc32 = CRC32()
crc32.update(s.toByteArray()) crc32.update(s.toByteArray())
@ -646,6 +662,51 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
notificationBuilder.addAction(replyAction) notificationBuilder.addAction(replyAction)
} }
// @RequiresApi(api = Build.VERSION_CODES.N)
// private fun addDiscardRecordingAvailableAction(notificationBuilder: NotificationCompat.Builder,
// systemNotificationId:
// Int) {
// val replyLabel = context!!.resources.getString(R.string.nc_reply)
// val remoteInput = RemoteInput.Builder(NotificationUtils.KEY_DIRECT_REPLY)
// .setLabel(replyLabel)
// .build()
//
// val replyPendingIntent = buildIntentForAction(
// DirectReplyReceiver::class.java,
// systemNotificationId,
// 0
// )
// val replyAction = NotificationCompat.Action.Builder(R.drawable.ic_reply, replyLabel, replyPendingIntent)
// .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
// .setShowsUserInterface(false)
// .setAllowGeneratedReplies(true)
// .addRemoteInput(remoteInput)
// .build()
// notificationBuilder.addAction(replyAction)
// }
//
// @RequiresApi(api = Build.VERSION_CODES.N)
// private fun addShareRecordingToChatAction(notificationBuilder: NotificationCompat.Builder, systemNotificationId:
// Int) {
// val replyLabel = context!!.resources.getString(R.string.nc_reply)
// val remoteInput = RemoteInput.Builder(NotificationUtils.KEY_DIRECT_REPLY)
// .setLabel(replyLabel)
// .build()
//
// val replyPendingIntent = buildIntentForAction(
// DirectReplyReceiver::class.java,
// systemNotificationId,
// 0
// )
// val replyAction = NotificationCompat.Action.Builder(R.drawable.ic_reply, replyLabel, replyPendingIntent)
// .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
// .setShowsUserInterface(false)
// .setAllowGeneratedReplies(true)
// .addRemoteInput(remoteInput)
// .build()
// notificationBuilder.addAction(replyAction)
// }
@RequiresApi(api = Build.VERSION_CODES.N) @RequiresApi(api = Build.VERSION_CODES.N)
private fun getStyle(person: Person, style: NotificationCompat.MessagingStyle?): NotificationCompat.MessagingStyle { private fun getStyle(person: Person, style: NotificationCompat.MessagingStyle?): NotificationCompat.MessagingStyle {
val newStyle = NotificationCompat.MessagingStyle(person) val newStyle = NotificationCompat.MessagingStyle(person)
@ -860,6 +921,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
}) })
} }
} }
private fun createMainActivityIntent(): Intent { private fun createMainActivityIntent(): Intent {
val intent = Intent(context, MainActivity::class.java) val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
@ -870,6 +932,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
intent.putExtras(bundle) intent.putExtras(bundle)
return intent return intent
} }
private fun getIntentToOpenConversation(): PendingIntent? { private fun getIntentToOpenConversation(): PendingIntent? {
val intent = Intent(context, MainActivity::class.java) val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK

View File

@ -267,7 +267,9 @@ object NotificationUtils {
fun cancelExistingNotificationsForRoom(context: Context?, conversationUser: User, roomTokenOrId: String) { fun cancelExistingNotificationsForRoom(context: Context?, conversationUser: User, roomTokenOrId: String) {
scanNotifications(context, conversationUser) { notificationManager, statusBarNotification, notification -> scanNotifications(context, conversationUser) { notificationManager, statusBarNotification, notification ->
if (roomTokenOrId == notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)) { if (roomTokenOrId == notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN) &&
!notification.extras.getBoolean(BundleKeys.KEY_NOTIFICATION_RESTRICT_DELETION)
) {
notificationManager.cancel(statusBarNotification.id) notificationManager.cancel(statusBarNotification.id)
} }
} }

View File

@ -83,4 +83,5 @@ object BundleKeys {
const val KEY_SWITCH_TO_ROOM_AND_START_CALL = "KEY_SWITCH_TO_ROOM_AND_START_CALL" const val KEY_SWITCH_TO_ROOM_AND_START_CALL = "KEY_SWITCH_TO_ROOM_AND_START_CALL"
const val KEY_IS_BREAKOUT_ROOM = "KEY_IS_BREAKOUT_ROOM" const val KEY_IS_BREAKOUT_ROOM = "KEY_IS_BREAKOUT_ROOM"
const val KEY_NOTIFICATION_RECORDING_NOTIFICATION = "KEY_NOTIFICATION_RECORDING_NOTIFICATION" const val KEY_NOTIFICATION_RECORDING_NOTIFICATION = "KEY_NOTIFICATION_RECORDING_NOTIFICATION"
const val KEY_NOTIFICATION_RESTRICT_DELETION = "KEY_NOTIFICATION_RESTRICT_DELETION"
} }