Blog Infos
Author
Published
Topics
, , , ,
Author
Published

 

Starting with Android 16, we have a new notification style Notification.ProgressStyle which we can use to create progress-centric notifications.

This article will teach us how to use this new style to provide live updates to end-users.

Important use-cases that we can implement with this are the following

  • Rideshare 🚕
  • Food Delivery 🚚 🥘
  • Navigation 🧭, etc.

ProgressStyle is quite customizable; It includes the following components that we can use to provide a live updates experience to end-users

  • Progress bar
  • Segments — A segment of the progress bar, which defines its length and color 🎨
  • Points — A point within the progress bar, defining its position and color 🎨
  • Tracker icon 🟢
  • Start 🎬 and end icon 🔚 for the progress bar

https://developer.android.com/static/about/versions/16/images/progress-style-anatomy.png

Guidelines for icons

https://developer.android.com/static/about/versions/16/images/progress-style-icon-anatomy.png

Implementation
  • In the app’s build.gradle set the compile SDK to Android 16

 

android {
    // Android 16
    compileSdk = 36

    defaultConfig {
        minSdk = 29
        // Android 16
        targetSdk = 36
    }
     
}

 

Make sure that the app has permission to post promoted notifications
  • We can use the canPostPromotedNotifications method of NotificationManager to check if our application has valid access or not.

 

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun checkInitialization(context: Context) {
    val canPostLiveUpdates = notificationManager.canPostPromotedNotifications()
}

 

Redirect the user to the settings to update their permissions
  • If the last step’s 👆 result is false We can redirect the user to the settings to update the settings, and then go from there.

 

val intent = Intent(ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT).setData(
    "package:${appContext.packageName}".toUri()),
)

(context as Activity).startActivityForResult(intent, PERMISSION_REQUEST_CODE)

 

Verify if the notification itself is promotable
  • We can use the hasPromotableCharacteristics of Notification to ensure the notification is valid for live update.

 

val isPromotable = notification.hasPromotableCharacteristics()

 

We will create a live update experience for the food delivery use case 🥘
  • Let’s create a notification channel

IMPORTANCE_MIN = 1does not qualify a notification as a live update

object LiveUpdatesNotificationManager {

    private lateinit var notificationManager: NotificationManager

    private lateinit var appContext: Context

    const val CHANNEL_ID = "live_updates_16_channel_id"

    private const val CHANNEL_NAME = "live_updates_16_channel_name"

    private const val NOTIFICATION_ID = 4321


fun createChannel(context: Context, notifManager: NotificationManager) {
    notificationManager = notifManager
    val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, IMPORTANCE_DEFAULT)
    appContext = context
    notificationManager.createNotificationChannel(channel)
}
  • For our use case, we will have the following five states
  1. Order placed or confirmed 👍
  2. Preparing 🧑‍🍳
  3. EnRoute 🛣️
  4. Arriving 🚗
  5. Delivered ✅
To get started, let’s start with the base notification.

 

fun buildBaseNotification(appContext: Context): Notification.Builder {
    return Notification.Builder(appContext, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setOngoing(true)
        .setColorized(true)
        .setColor(Color.GRAY)
}

 

We need to set the style to ProgressStyle, that can be a live update

So let’s create a Progress style for each case

  • Using the previous step’s👆 base notification, we will build upon it
Order placed or confirmed — Step 1️⃣

 

fun buildBaseNotification(): Notification.Builder {
    return buildBaseNotification(appContext, INITIALIZING)
        .setContentTitle("You order is being placed")
        .setContentText("Confirming with Spicy7...")
}

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun buildBaseProgressStyle(): ProgressStyle {
    val progressStyle = ProgressStyle()
        .setProgressPoints(
            listOf(
                ProgressStyle.Point(25).setColor(Color.MAGENTA),
                ProgressStyle.Point(50).setColor(Color.RED),
                ProgressStyle.Point(75).setColor(Color.GREEN)
            )
        ).setProgressSegments(
            listOf(
                ProgressStyle.Segment(25).setColor(Color.BLUE),
                ProgressStyle.Segment(25).setColor(Color.MAGENTA),
                ProgressStyle.Segment(25).setColor(Color.LTGRAY),
                ProgressStyle.Segment(25).setColor(Color.RED)
            )
        )
     return progressStyle
}

 

So here we started with 3 points and four segments.

Result

Step 1 — Result

Preparing 🧑‍🍳 — Step 2️⃣
  • We have updated the progress to 25 and added the large icon to the existing notification.
  • Title and text have been updated
    .setContentTitle(“Your order is being prepared”)
    .setContentText(“Next step will be delivery”)
  • We will keep three points and four segments.

 

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun buildNotification(): Notification.Builder {
    return buildBaseNotification(appContext, FOOD_PREPARATION)
        .setContentTitle("Your order is being prepared")
        .setContentText("Next step will be delivery")
        .setLargeIcon(
            IconCompat.createWithResource(
                appContext, R.drawable.ic_notif_large,
            ).toIcon(appContext),
        )
        .setStyle(buildBaseProgressStyle().setProgress(25))
}

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun buildBaseProgressStyle(): ProgressStyle {
    // same like step 1.
    
}

 

Result

Step 2— Result

EnRoute 🛣️ — Step 3️⃣
  • Here, we set the progress to 50 and set the progress tracker icon 🥯
  • Title and text have been updated
    .setContentTitle(“Your order is on its way”)
    .setContentText(“Enroute to destination”)
  • We show one points(25), and four segments

 

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun buildNotification(): Notification.Builder {
    return buildBaseNotification(appContext, FOOD_ENROUTE)
    .setContentTitle("Your order is on its way")
    .setContentText("Enroute to destination")
    .setStyle(
        buildBaseProgressStyle()
            .setProgressTrackerIcon(
                IconCompat.createWithResource(
                    appContext, R.drawable.shopping_bag,
                ).toIcon(appContext),
            )
            .setProgress(50),
    )
    .setLargeIcon(
        IconCompat.createWithResource(
            appContext, R.drawable.ic_notif_large,
        ).toIcon(appContext),
    )
}

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun buildBaseProgressStyle(): ProgressStyle {
    val progressStyle = ProgressStyle()
    .setProgressPoints(
        listOf(
            ProgressStyle.Point(25).setColor(Color.MAGENTA)
        )
    ).setProgressSegments(
        listOf(
            ProgressStyle.Segment(25).setColor(Color.BLUE),
            ProgressStyle.Segment(25).setColor(Color.MAGENTA),
            ProgressStyle.Segment(25).setColor(Color.LTGRAY),
            ProgressStyle.Segment(25).setColor(Color.RED)
        )
    )
  
    return progressStyle
}
Result

Step 3— Result

Arriving 🚗 — Step 4️⃣
  • Here, we set the progress to 75 and set the progress tracker icon 🥯
  • Title and text have been updated
    .setContentTitle(“Your order is arriving...”)
    .setContentText(“Enjoy.”)
  • We show two points(25, 50), and four segments

 

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun buildNotification(): Notification.Builder {
    return buildBaseNotification(appContext, FOOD_ARRIVING)
    .setContentTitle("Your order is arriving...")
    .setContentText("Enjoy 😋")
    .setStyle(
        buildBaseProgressStyle(FOOD_ARRIVING)
            .setProgressTrackerIcon(
                IconCompat.createWithResource(
                    appContext, R.drawable.local_shipping,
                ).toIcon(appContext),
            )
            .setProgress(75),
    )
    .setLargeIcon(
        IconCompat.createWithResource(
            appContext, R.drawable.ic_notif_large,
        ).toIcon(appContext),
    )
}

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun buildBaseProgressStyle(): ProgressStyle {
    val progressStyle = ProgressStyle()
    .setProgressPoints(
        listOf(
            ProgressStyle.Point(25).setColor(Color.MAGENTA),
            ProgressStyle.Point(50).setColor(Color.RED),
        )
    ).setProgressSegments(
        listOf(
            ProgressStyle.Segment(25).setColor(Color.BLUE),
            ProgressStyle.Segment(25).setColor(Color.MAGENTA),
            ProgressStyle.Segment(25).setColor(Color.LTGRAY),
            ProgressStyle.Segment(25).setColor(Color.RED)
        )
    )
  
    return progressStyle
}sasa
Result

Step 4— Result

Delivered ✅ — Step 5️⃣
  • Here, we set the progress to 100 and set the progress tracker icon ✅
  • Title and text have been updated
    .setContentTitle(“Your order is complete.”)
    .setContentText(“Thank you for using our app.”)
  • We show three points(25, 50, 75), and four segments

 

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun buildNotification(): Notification.Builder {
    return buildBaseNotification(appContext, ORDER_COMPLETE)
    .setContentTitle("Your order is complete.")
    .setContentText("Thank you for using our app.")
    .setStyle(
        buildBaseProgressStyle(ORDER_COMPLETE)
            .setProgressTrackerIcon(
                IconCompat.createWithResource(
                    appContext, R.drawable.check_box,
                ).toIcon(appContext),
            )
            .setProgress(100),
    )
    .setLargeIcon(
        IconCompat.createWithResource(
            appContext, R.drawable.ic_notif_large,
        ).toIcon(appContext),
    )
}

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
fun buildBaseProgressStyle(): ProgressStyle {
    val progressStyle = ProgressStyle()
    .setProgressPoints(
        listOf(
            ProgressStyle.Point(25).setColor(Color.MAGENTA),
            ProgressStyle.Point(50).setColor(Color.RED),
            ProgressStyle.Point(75).setColor(Color.LTGRAY)
        )
    )
  
    return progressStyle
}
Result

Step 5 — Result

A few important points
  • Points at the start and end will not show in the progress bar
  • DEFAULT_PROGRESS_MAX is 100
  • MAX_PROGRESS_POINT_LIMIT is 4
  • Progress bar’s max value is calculated based on the segments
Sample code

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

No results found.

Jobs

Menu