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

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

,

Bringing Android 13 to Tesla vehicles with Flutter Web

Did you know that you can use your favorite Android apps while driving your Tesla? Join me in this session to learn how the Tesla Android Project made it all possible with Flutter Web on…
Watch Video

Bringing Android 13 to Tesla vehicles with Flutter Web

Michał Gapiński
Senior Software Engineer
HappyByte

Bringing Android 13 to Tesla vehicles with Flutter Web

Michał Gapiński
Senior Software Engi ...
HappyByte

Bringing Android 13 to Tesla vehicles with Flutter Web

Michał Gapińsk ...
Senior Software Engineer
HappyByte

Jobs

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
While Targeting Android 13 , OnbackPressed Override Function is deprecated😢. Usually, we used to…
READ MORE
blog
In this article, we will explore Android 13’s new clipboard UI, as well as…
READ MORE
blog
App launcher icons, the very first interaction that someone has with your app is…
READ MORE
blog
As we know, with every release, Android deprecates some APIs and introduces new ones…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

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

Menu