Ditch the Notification and Show an Activity on Your Android Lock Screen Instead

Written by victorbrndls | Published 2023/03/16
Tech Story Tags: android | kotlin | programming | tutorial | coding | guide | technology | phone

TLDRBy default, Android will show the same notification it shows when the device is unlocked, but in some cases, such as a phone call, you might want to display a full-screen activity. Here we’ll create the notification that will be displayed on the lock screen. That notification will be used later to show an Activity on the look screen.via the TL;DR App

Today we’re gonna learn how to show a full screen activity instead of a notification when the device is locked.

By default, Android will show the same notification it shows when the device is unlocked but in some cases, such as a phone call, you might want to display a full-screen activity.

You can find the source code here.

Creating The Notification

Let’s start by creating a simple notification that’ll be used later to show an Activity on the look screen.

The first thing we need to do before creating the notification is to create the channel to display it.

private const val CHANNEL_ID = "heads_up_alerts"
private const val CHANNEL_NAME = "Heads Up Alerts"

private val notificationManager = NotificationManagerCompat.from(context)

private fun createNotificationChannel() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return

    val channel = NotificationChannel(
        CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH
    ).apply {
        lockscreenVisibility = Notification.VISIBILITY_PUBLIC
    }

    notificationManager.createNotificationChannel(channel)
}

First, we retrieve the NotificationManager from NotificationManagerCompat. That’s the interface used for dealing with notifications on Android. Then we create a NotificationChannel that takes the channel’s id, name and importance as arguments. It’s advised to use NotificationManager.IMPORTANCE_HIGH to increase the chances of the notification appearing as a heads-up notification. We also change the lockscreenVisibility to Notification.VISIBILITY_PUBLIC to tell Android that the notification can be shown on the lock screen. Finally, we call notificationManager.createNotificationChannel to register the channel.

Up until Android Nought (25), there was no need to create notification channels, that’s why there’s a guard cause at the beginning of the method.

When Should I Create the Channel?

There’s no problem in calling createNotificationChannel multiple times with the same channel, Android will ignore it if there’s an existing channel with the same id.

You should register your channels as early as possible, preferably when Application.onCreate is called.

Channels are immutable; if you need to change some channel configuration, you’ll either have to delete the app or change the channel’s id.

Creating a Simple Notification

Now that we have created a channel, we can create the notification.

private fun createNotification(): Notification {
    val contentIntent = Intent(context, HomeActivity::class.java)
    val contentPendingIntent = PendingIntent.getActivity(context, 0, contentIntent, 0)
    
    return NotificationCompat.Builder(context, CHANNEL_ID)
        .setSmallIcon(R.drawable.notifications_active_black_24)
        .setColor(ResourcesCompat.getColor(context.resources, R.color.purple_200, null))
        .setContentTitle(context.getString(R.string.notification_title))
        .setAutoCancel(true)
        .setContentIntent(contentPendingIntent)
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .build()
}

First, we start by creating a PendingIntent, that’s the intent that will be called when the notification is clicked. Here, we’ll simply start an activity. Then we call NotificationCompat.Builder to define how the notification will look like. The CHANNEL_ID parameter has to have the same id we used earlier to create the channel. If you want to learn how to customize your notification, you can take a look at the Android Documentation.

The next step is simply calling notificationManager to show the notification. The notification id can be any number; it’s used only if you need to interact with the notification later.

const val NOTIFICATION_ID = 24756

notificationManager.notify(NOTIFICATION_ID, createNotification())

That’s what you should see when your notification is displayed.

Creating the Lock Screen Activity

Now we’ll create the Activity that’ll be displayed on the lock screen. That activity is very similar to normal activity, but there are two things you need to change for it to appear on the lock screen.

The first is calling showWhenLockedAndTurnScreenOn after onCreate to define that the activity can appear on the lock screen and that the screen should be turned on when it appears. I added the method to the activity, but you can easily add that as an extension to the Activity in case you use it in other places.

class LockscreenActivity : AppCompatActivity() {

    private lateinit var binding: ActivityLockscreenBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        showWhenLockedAndTurnScreenOn()
        super.onCreate(savedInstanceState)

        binding = ActivityLockscreenBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }

    private fun showWhenLockedAndTurnScreenOn() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
            setShowWhenLocked(true)
            setTurnScreenOn(true)
        } else {
            window.addFlags(
                WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                        or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
            )
        }
    }
}

The second thing is changing the manifest definition by adding launchMode and showOnLockScreen.

<activity
  android:name=".presentation.LockscreenActivity"
  android:launchMode="singleTop"
  android:showOnLockScreen="true" />

That’s it. You’ve created an activity that can appear on the lock screen. The last thing we need to do is to tell Android that we want that activity to appear on the lock screen instead of the notification.

Adding the Activity to Notification

We’ll have to modify the createNotification method we defined earlier. We need to create another PendingIntent that’ll start the activity that’ll be shown on the lock screen. We then pass that intent to setFullScreenIntent. It’s also important to add a category such as ALARM or CALL to increase the chances of it appearing on the lock screen.

    private fun createNotification(): Notification {
        val contentIntent = Intent(context, HomeActivity::class.java)
        val contentPendingIntent = PendingIntent.getActivity(context, 0, contentIntent, 0)

        val fullScreenIntent = Intent(context, LockscreenActivity::class.java)
        val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, fullScreenIntent, 0)

        return NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.notifications_active_black_24)
            .setColor(ResourcesCompat.getColor(context.resources, R.color.purple_200, null))
            .setContentTitle(context.getString(R.string.notification_title))
            .setAutoCancel(true)
            .setContentIntent(contentPendingIntent)
            .setFullScreenIntent(fullScreenPendingIntent, true)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setCategory(NotificationCompat.CATEGORY_ALARM)
            .build()
    }

Here’s a video of the end result.


It’s not Working !!!

For some of you, the activity might not appear on the lock screen, and that’s because of your phone. Not all phones allow full-screen intents by default. I have a Xiaomi, and it’s not enabled by default.

To enable it, you have to go to the app configuration -> Other permissions -> Show On Lock screen.

The notification will also not appear if you have an existing notification with the same id that has not been dismissed. Ideally, you should cancel the notification by calling notificationManager.cancel(id) when the lock screen activity is destroyed.

Conclusion

Android notifications are a great way to notify your users they need to do something, but they might not work well when the phone is locked. Full-screen activities come to solve that problem, allowing you to show the activity even if the phone is locked.

The source code can be found here.

Resources

How to manage incoming video call for every Android OS version with FCM notifications

Show an urgent message

Photo by Rami Al-zayat on Unsplash

Also published here.


Written by victorbrndls | I like understanding how things work and why they work like that, this is what drives me to learn new things
Published by HackerNoon on 2023/03/16