Search code examples
androidandroid-intentnotificationlistenerservice

How do I open another application after reading its push notification in my Android app?


I have an app where I'm displaying notifications from chat apps after reading the with a Notification listener service and storing them in a room database.

Now I want to open the specific chat the notification is for in that app when the user clicks on it in my app UI (displayed in a recycler view). Right now, I'm just launching the apps by package name.

Is it possible to simulate clicking on the notification or trigger whatever action the notification has?

@RequiresApi(Build.VERSION_CODES.O)
override fun onNotificationPosted(sbn: StatusBarNotification) {
    Log.d(TAG, "oN NOTIFY")

    if (isConnected) {

        val notification = sbn.notification
        val extras = notification.extras
        val packageName = sbn.packageName

        // Extract the message content
        val title = extras.getString(Notification.EXTRA_TITLE) ?: ""
        val message = extras.getString(Notification.EXTRA_TEXT) ?: extras.getString(Notification.EXTRA_SUB_TEXT) ?: ""

        // Check if the notification is from a chat app and contains chat notification
        if (conversationApps.contains(packageName)
            && invalidNotificationText.none { message.contains(it) }) {

            // Extract the sender/group image
            val senderImageIcon = extras.getParcelable<Parcelable>(Notification.EXTRA_LARGE_ICON) ?: extras.getParcelable<Parcelable>(Notification.EXTRA_PICTURE)
            Log.e(TAG, senderImageIcon.toString())

            val senderImageBitmap: Bitmap? = makeBitmap(senderImageIcon)
            val senderImageByteArray =
                senderImageBitmap?.let { getByteArrayFromBitmap(it) } ?: byteArrayOf()

            // Extract the app icon
            val pm = applicationContext.packageManager
            val appIcon = pm.getApplicationIcon(packageName)
            val appIconBitmap: Bitmap? = makeBitmap(appIcon)
            val appIconByteArray =
                appIconBitmap?.let { getByteArrayFromBitmap(it) } ?: byteArrayOf()

            // Create conversation object
            val conversation = ConversationEntity(
                0,
                packageName,
                title,
                message,
                senderImageByteArray,
                appIconByteArray,
            )

            CoroutineScope(Dispatchers.IO).launch {
                delay(500)
                conversationRepository.deleteByPackageNameAndMessage(packageName, title, message)
                conversationRepository.insertConversation(conversation)
            }

        }

    }
}

Solution

  • I've actually been able to solve the issue.

    To reply a notification with a reply action, I'm "recreating" the reply action from the notification with code from Rob J's article. I actually copied most of the implementation from this github repository shared under another Stack overflow question.

    Creating the reply action looks like this:

    override fun onNotificationPosted(sbn: StatusBarNotification) {
         val action: Action? = NotificationUtils.getQuickReplyAction(sbn.notification, getPackageName())
         ...
    }
    

    and you can send the reply like this:

    action.sendReply(myApplicationContext, "replyText")
    

    Additionally, to open the chat (Without replying the message), I'm getting the contentIntent (a Pending Intent) from the notification in onNotificationPosted like so:

    override fun onNotificationPosted(sbn: StatusBarNotification) {
    
                val notification = sbn.notification
                val contentIntent = notification.contentIntent
    
                ...
    }
    

    To open the notification's respective app, I just call the send() method on the pending intent.

    contentIntent.send()