Open In App

Android progress notifications in Kotlin

Last Updated : 05 Feb, 2025
Summarize
Comments
Improve
Suggest changes
Like Article
Like
Share
Report
News Follow

In this tutorial you’ll learn how to create a basic Progress Notification (Indeterminate progress indicator and Fixed-duration progress indicator) for Android using Kotlin. Before we begin, let us first understand the components of a Notification in Android.

Components of a Notification:

  1. Small Icon – Required, can be set with setSmallIcon().
  2. Application Name – Provided by the system.
  3. Time Stamp – Provided by the system but can be overridden.
  4. Large Icon – Optional, can be set with setLargeIcon().
  5. Title – Optional, can be set with setContentTitle().
  6. Text – Optional, can be set with setContentText().

Note : Since the introduction of Android version 8 (Android Oreo), it is now compulsory to categorize all the notifications into categories called Notification Channels. This is for the convenience of users and also developers. The image below shows us a notification channel named ‘Progress Notification’.

Step by Step Implementation:

Step 1: Create a New Project

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language. Choose the API level according to your choice( Here we have chosen API Level 26).

Step 2:Adding Permission for notification

Android 13 (API level 33) and higher need a permission for posting notifications from an app. For this, declare permission in the manifest file. Please manually make sure that the permission for notifications is provided for this app on phone.

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

Step 3: Working with the activity_main.xml file

Go to the activity_main.xml file and refer to the following code. We are just going to add a basic button to trigger the notification.

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    tools:context=".MainActivity">

    <!-- Button for sending notification-->
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:backgroundTint="@color/green"
        android:text="Send Notification"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Step 4: Working with the MainActivity.kt file

Go to the MainActivity.kt file and refer to the following code. Below is the code for the MainActivity.kt file. Comments are added inside the code to understand the code in more detail.

MainActivity.kt:

package org.geeksforgeeks.demo

import android.Manifest
import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.os.SystemClock
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat

class MainActivity : AppCompatActivity() {
    private lateinit var button: Button
    private lateinit var notificationManager: NotificationManagerCompat
      
    override fun onCreate(savedInstanceState: Bundle?) 
    {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button = findViewById(R.id.button)
        notificationManager = NotificationManagerCompat.from(this)

        // Create a notification channel (required for Android 8.0 and higher)
        createNotificationChannel()

        button.setOnClickListener {
            // Request runtime permission for notifications on Android 13 and higher
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                if (ActivityCompat.checkSelfPermission(
                        this,
                        Manifest.permission.POST_NOTIFICATIONS
                    ) != PackageManager.PERMISSION_GRANTED
                ) {
                    ActivityCompat.requestPermissions(
                        this,
                        arrayOf(Manifest.permission.POST_NOTIFICATIONS),
                        101
                    )
                    return@setOnClickListener
                }
            }
            sendNotification() // Trigger the notification
        }
    }

    /**
     * Create a notification channel for devices running Android 8.0 or higher.
     * A channel groups notifications with similar behavior.
     */
    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationChannel = NotificationChannel(
                CHANNEL_ID,
                CHANNEL_NAME,
                NotificationManager.IMPORTANCE_HIGH
            )

            val notificationManager =
                getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(notificationChannel)
        }
    }

    /**
     * Build and send a notification with a custom layout and action.
     */
    @SuppressLint("MissingPermission")
    private fun sendNotification() {
        val intent = Intent(this, MainActivity::class.java)
            .apply {
                flags = Intent.FLAG_ACTIVITY_NEW_TASK or
                        Intent.FLAG_ACTIVITY_CLEAR_TASK
            }

        val pendingIntent: PendingIntent = PendingIntent.getActivity(
            this, 0, intent, PendingIntent.FLAG_IMMUTABLE
        )

        //Sets the maximum progress as 100
        val progressMax = 100

        // Build the notification
        val builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.gfg_logo) // Notification icon
            .setContentTitle("GeeksforGeeks") // Title displayed in the notification
            .setContentText("Downloading...") // Text displayed in the notification
            .setAutoCancel(true) // Dismiss notification when tapped
            .setPriority(NotificationCompat.PRIORITY_HIGH) // Notification priority for better visibility
            .setOngoing(true)
            .setOnlyAlertOnce(true)
            .setProgress(progressMax, 0, true)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)

        // Display the notification
        notificationManager.notify(NOTIFICATION_ID, builder.build())

        Thread(Runnable{
            SystemClock.sleep(2000)
            var progress = 0
            while (progress <= progressMax) {
                SystemClock.sleep(
                    1000
                )
                progress += 7
                //Use this to make it a Fixed-duration progress indicator notification

                builder.setContentText("$progress%")
                .setProgress(progressMax, progress, false)

                notificationManager.notify(1, builder.build())
            }

            builder.setContentText("Download complete")
                .setProgress(0, 0, false)
                .setOngoing(false)
            notificationManager.notify(1, builder.build())
        }).start()
    }

    companion object {
          // Unique channel ID for notifications
        const val CHANNEL_ID = "i.apps.notifications"
          
        // Unique identifier for the notification
        const val NOTIFICATION_ID = 1234 
          
        // Description for the notification channel
        const val CHANNEL_NAME = "Test notification"  
    }
}

Output:



Next Article
Article Tags :

Similar Reads

three90RightbarBannerImg