Blog Infos
Author
Published
Topics
Author
Published

Today, We will explore the New notification 🔔 runtime permission that was added in Android Tiramisu(13).

public static final String POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS";
App behavior based on Action
  1. Allow:
    when the user taps on allow app can do the following:
    Send notifications 🔔
    – All notification channels of an app are allowed.
    – The app can post notifications related to foreground services.
  2. Don’t allow
    when the user taps on don’t allow:

    – App can’t send the notification 🔕
    – All notification channels are blocked
  3. Dismissed the dialog without any action
    If the app is eligible for a temporary notification permission grant, the system preserves the temporary grant otherwise, the app can’t send notifications.
Behavior on newly installed apps

If the device is running Android13 then the app’s notifications are off bydefault

When permission dialog shows up it depends on the targetSdk of the app

  • Android13: We have full control when we want to ask the user for permission
  • Android 12L or lower: The system will show the permission dialog when the app creates its first notification channel
Effects on updates to existing apps

The system grants temporary permission to the app if it falls under the category of eligible apps.

The length of a temporary grant depends on the targetSDK

  • Android13: valid until the first-time app launches the activity
  • Android 12L or lower: valid until the user selects an option in the permission dialog

If the user dismiss the permission dialog without selecting an option, the system will persist the temporary grant

Let’s see it in action

 

Notification Permission Dialog

 

  1. Declare the permission in the app’s manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapplication">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application>
</application>
</manifest>

2. Ask for permission from the user

package com.example.myapplication
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.widget.Button
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.google.android.material.snackbar.Snackbar
/**
* @author Nav Singh
*/
class MainActivity : AppCompatActivity() {
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
// Permission is granted. Continue the action or workflow in your
// app.
sendNotification(this)
} else {
// Explain to the user that the feature is unavailable because the
// features requires a permission that the user has denied. At the
// same time, respect the user's decision. Don't link to system
// settings in an effort to convince the user to change their
// decision.
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val message = intent?.getStringExtra(NOTIFICATION_MESSAGE_TAG)
findViewById<TextView>(R.id.tv_message).text = message
findViewById<Button>(R.id.click).setOnClickListener {
when {
ContextCompat.checkSelfPermission(
this, Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED -> {
// You can use the API that requires the permission.
Log.e(TAG, "onCreate: PERMISSION GRANTED")
sendNotification(this)
}
shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS) -> {
Snackbar.make(
findViewById(R.id.parent_layout),
"Notification blocked",
Snackbar.LENGTH_LONG
).setAction("Settings") {
// Responds to click on the action
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val uri: Uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivity(intent)
}.show()
}
else -> {
// The registered ActivityResultCallback gets the result of this request
requestPermissionLauncher.launch(
Manifest.permission.POST_NOTIFICATIONS
)
}
}
}
}
companion object {
const val TAG = "MainActivity"
const val NOTIFICATION_MESSAGE_TAG = "message from notification"
fun newIntent(context: Context) = Intent(context, MainActivity::class.java).apply {
putExtra(
NOTIFICATION_MESSAGE_TAG, "Hi ☕\uD83C\uDF77\uD83C\uDF70"
)
}
}
}
view raw MainActivity.kt hosted with ❤ by GitHub

3. Create and send Notification

package com.example.myapplication
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.Context
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.TaskStackBuilder
const val NOTIFICATION_CHANNEL_ID = BuildConfig.APPLICATION_ID + ".channel"
/**
* @author Nav Singh
*/
fun sendNotification(context: Context) {
val notificationManager = context
.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// We need to create a NotificationChannel associated with our CHANNEL_ID before sending a notification.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID) == null
) {
val name = context.getString(R.string.app_name)
val channel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
name,
NotificationManager.IMPORTANCE_DEFAULT
)
notificationManager.createNotificationChannel(channel)
}
val intent = MainActivity.newIntent(context.applicationContext)
// create a pending intent that opens MainActivity when the user clicks on the notification
val stackBuilder = TaskStackBuilder.create(context)
.addParentStack(MainActivity::class.java)
.addNextIntent(intent)
val notificationPendingIntent = stackBuilder
.getPendingIntent(getUniqueId(), FLAG_IMMUTABLE)
// build the notification object with the data to be shown
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Title")
.setContentText("Content goes here")
.setContentIntent(notificationPendingIntent)
.setAutoCancel(true)
.build()
notificationManager.notify(getUniqueId(), notification)
}
private fun getUniqueId() = ((System.currentTimeMillis() % 10000).toInt())
Demo

 

Allow notification permission

Job Offers

Job Offers


    Android Developer

    Small and Modern GmbH
    Hamburg, Remote (Germany)
    • Full Time
    apply now

    Senior Android Developer (Remote)

    Komoot
    Europe
    • Full Time
    apply now

    Android Build Engineer

    Pinterest
    San Francisco, CA | Seattle, WA
    • Full Time
    apply now
Load more listings

OUR VIDEO RECOMMENDATION

,

Leveling Up Your Tests

We all know about TDD and Unit Testing, and even screenshot testing, but sometimes we do not need to embrace a new paradigm to make our tests better. These are several techniques I have adopted…
Watch Video

Leveling Up Your Tests

Jobs

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
How to use the new feature from Android 13 to display your app in…
READ MORE
blog
In the recently published Android 13 Developer Preview blog post, Dave Burke noted two…
READ MORE
blog
Google recently announced the first Developer Preview of Android 13, while there are a…
READ MORE
blog
Part of the Material You concept is Themed Icons. It means that all icons…
READ MORE

Leave a Reply

Your email address will not be published.

Fill out this field
Fill out this field
Please enter a valid email address.

Menu