Search code examples
androidandroid-intentandroid-activityandroid-notificationsalarmmanager

Full screen intent doesn't display on lock screen


So in my app when the time is up I want to launch an activity that notifies the user and then lets them dismiss the alarm.

I try to achieve it by scheduling an exact alarm and then launching a high priority notification with full-screen intent from my AlarmReceiver's onReceive(). The problem is that the activity doesn't launch when the screen is locked, all I receive is a heads-up notification that doesn't even turn the screen on, nor vibrates. It doesn't launch on my phone (Xiaomi X4 with Android 7.1.2) but it did on another phone I tried (Samsung Galaxy A5 with Android 6). I know that this is possible to achieve on my phone as I've observed that other apps like clock, phone, whatsapp and so on can do this.

Androidmanifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.app">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
    <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.App">
        <activity
            android:taskAffinity=""
            android:launchMode="singleInstance"
            android:showForAllUsers="true"
            android:excludeFromRecents="true"
            android:name=".TimeIsUpActivity" />


        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:showOnLockScreen="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name=".AlarmReceiver"
            android:enabled="true" />
    </application>

</manifest>

This is how I set up the alarm:

        val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
            PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        }

        val seconds = 5

        alarmMgr.setExactAndAllowWhileIdle(
            AlarmManager.ELAPSED_REALTIME_WAKEUP,
            SystemClock.elapsedRealtime() + seconds*1000,
            alarmIntent
        )

My alarm receiver:

class AlarmReceiver: BroadcastReceiver(){
    override fun onReceive(context: Context?, intent: Intent?) {
        context?.apply {
            val fullScreenIntent = Intent(this, TimeIsUpActivity::class.java)
            fullScreenIntent.flags =
                Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or
                    Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS or Intent.FLAG_ACTIVITY_NO_USER_ACTION

            val fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
                fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)

            val builder = NotificationCompat.Builder(this, getString(R.string.channel_id))
                .setContentTitle("Time is up")
                .setContentText("Tap to dismiss")
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setContentIntent(fullScreenPendingIntent)
                .setSmallIcon(R.drawable.ic_add)
                .setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
                .setOngoing(true)
                .setLights(0xFFFFFF, 1000, 1000)
                .setCategory(NotificationCompat.CATEGORY_ALARM)
                .setPriority(NotificationCompat.PRIORITY_MAX)
                .setFullScreenIntent(fullScreenPendingIntent, true)


            val notificationId = Random().nextInt()
            val notification = builder.build()

            with(NotificationManagerCompat.from(this)) {
                notify(notificationId, notification)
            }
        }
    }
}

The activity I am trying to launch:

class TimeIsUpActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        turnScreenOnAndKeyguardOff()
        setContentView(R.layout.activity_time_is_up)
    }

    private fun turnScreenOnAndKeyguardOff() {
        if (Build.VERSION.SDK_INT >= 27) {
            setShowWhenLocked(true)
            setTurnScreenOn(true)
            (getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager).also {
                it.requestDismissKeyguard(this, null)
            }
        }

        window.addFlags(
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
                    WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON or
                    WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
                    WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
    }
}

Please help me.


Solution

  • I found that it's because Xiaomi devices don't allow apps to show on lock screen by default. To allow it one has to go to settings -> permissions -> other permissions -> find your app -> check "Show on Lock screen". It might be different on newer devices.