Android full screen notification won't show over the lock screen
Asked Answered
D

5

11

I'm trying to create an android full screen notification to show an activity over the lock screen, like an alarm clock.

The notification always occurs, but the activity is never started over the lock screen; it just rings and shows a notification icon on the lock screen if the phone is off. It shows a heads up notification if the phone is on as expected. A debug print indicates the notification channel is successfully registered at importance level HIGH/4 as requested.

I've tried it on 5 different android device versions: Android 10, 8.0.0, 6.0.1, 5.1.1

I've followed the android developers documentation linked below. I also linked a couple similar stack overflow questions.

https://developer.android.com/training/notify-user/time-sensitive

https://developer.android.com/training/notify-user/build-notification#urgent-message

Full screen intent not starting the activity but do show a notification on android 10

FullScreen Notification

Below is a very minimal version of the application code, an activity with 1 button to schedule the notification in the future with a broadcast receiver so it fires after the screen is locked.

    compileSdkVersion 29
    buildToolsVersion "29.0.2"

    minSdkVersion 25
    targetSdkVersion 29

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

public class AppReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (FullscreenActivity.FULL_SCREEN_ACTION.equals(intent.getAction()))
            FullscreenActivity.CreateFullScreenNotification(context);
    }
}

public class FullscreenActivity extends AppCompatActivity {

    private static final String CHANNEL_ID = "my_channel";
    static final String FULL_SCREEN_ACTION = "FullScreenAction";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_fullscreen);
        createNotificationChannel(this);
    }

    /**
     * Use button to set alarm manager with a pending intent to create the full screen notification
     * after use has time to shut off device to test with the lock screen showing
     */
    public void buttonClick(View view) {
        Intent intent = new Intent(this, AppReceiver.class);
        intent.setAction(FULL_SCREEN_ACTION);
        PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
        if (am != null) {
            am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 15000, pi);
        }
    }

    static void CreateFullScreenNotification(Context context) {
        Intent fullScreenIntent = new Intent(context, FullscreenActivity.class);
        fullScreenIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);//?
        PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(context, 0,
                fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(context, CHANNEL_ID)
                        .setSmallIcon(R.drawable.ic_launcher_background)
                        .setContentTitle("Full Screen Alarm Test")
                        .setContentText("This is a test")
                        .setPriority(NotificationCompat.PRIORITY_HIGH)
                        .setCategory(NotificationCompat.CATEGORY_CALL)
                        .setDefaults(NotificationCompat.DEFAULT_ALL) //?
                        .setFullScreenIntent(fullScreenPendingIntent, true);

        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
        notificationManager.notify(1, notificationBuilder.build());
    }

    private static void createNotificationChannel(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);

            if (notificationManager != null && notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);
                channel.setDescription("channel_description");
                notificationManager.createNotificationChannel(channel);
            }

            //DEBUG print registered channel importance
            if (notificationManager != null && notificationManager.getNotificationChannel(CHANNEL_ID) != null) {
                Log.d("FullScreenActivity", "notification channel importance is " + notificationManager.getNotificationChannel(CHANNEL_ID).getImportance());
            }
        }
    }
}
Delorenzo answered 4/3, 2020 at 22:59 Comment(0)
D
11

I was finally able to get this to work after finding this answer for an incoming call: https://mcmap.net/q/751519/-how-to-show-the-incoming-call-screen-when-the-screen-is-locked

The part missing from the android document examples for full screen intents was that the activity the full screen intent tries to show needs a couple WindowManager.LayoutParams flags set: FLAG_SHOW_WHEN_LOCKED and FLAG_TURN_SCREEN_ON.

Here's the final minimal test app code I hope is useful for others trying to do an alarm clock type app. I tested successfully on the 4 OS versions listed above with target sdk 29 and minimum sdk 15. The only manifest permission needed was USE_FULL_SCREEN_INTENT and only for devices running android Q/29 and above.

public class AppReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (FullscreenActivity.FULL_SCREEN_ACTION.equals(intent.getAction()))
            FullscreenActivity.CreateFullScreenNotification(context);
    }
}

public class FullscreenActivity extends AppCompatActivity {

    private static final String CHANNEL_ID = "my_channel";
    static final String FULL_SCREEN_ACTION = "full_screen_action";
    static final int NOTIFICATION_ID = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_fullscreen);
        createNotificationChannel(this);

        //set flags so activity is showed when phone is off (on lock screen)
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    /**
     * Use button to set alarm manager with a pending intent to create the full screen notification
     * after use has time to shut off device to test with the lock screen showing
     */
    public void buttonClick(View view) {
        Intent intent = new Intent(FULL_SCREEN_ACTION, null, this, AppReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
        if (alarmManager != null) {
            alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 15000, pendingIntent);
        }

        NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID); //cancel last notification for repeated tests
    }

    static void CreateFullScreenNotification(Context context) {
        Intent intent = new Intent(context, FullscreenActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder notificationBuilder =
                new NotificationCompat.Builder(context, CHANNEL_ID)
                        .setSmallIcon(R.drawable.ic_launcher_background)
                        .setContentTitle("Full Screen Alarm Test")
                        .setContentText("This is a test")
                        .setPriority(NotificationCompat.PRIORITY_MAX)
                        .setCategory(NotificationCompat.CATEGORY_ALARM)
                        .setContentIntent(pendingIntent)
                        .setFullScreenIntent(pendingIntent, true);
        NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notificationBuilder.build());
    }

    private static void createNotificationChannel(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

            if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) {
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);
                channel.setDescription("channel_description");
                notificationManager.createNotificationChannel(channel);
            }
        }
    }
}
Delorenzo answered 5/3, 2020 at 20:3 Comment(4)
Nice one, thanks for this. As usual, Google's documentation just causes more headaches.Northeastward
How does this work. In my case, I am throwing a notification with full screen intent from a background service. The notification sits there but the activity does not launch until I unlock the device and actually click on the notification.Caste
@Northeastward How to show activity when device lock. In some device it's not working like xiomi.Hoyt
@RajGohel I found this article and solution is given under "It's not working" and apparently this is specific to Xiaomi where permission to Show on Lock Screen is disabled by defaultBauske
V
3
//use the following code it will work

//also put this in your Manifest.xml

 <uses-permission android:name="android.permission.WAKE_LOCK"/>
//put this in manifest in your specific activity you want to show on lock 
//screen
  android:showWhenLocked="true"

  getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
    getWindow().addFlags(AccessibilityEventCompat.TYPE_WINDOWS_CHANGED);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Venita answered 19/3, 2021 at 11:8 Comment(0)
M
1

As per other answers posted here, the two flags FLAG_SHOW_WHEN_LOCKED and FLAG_TURN_SCREEN_ON are crucial for Android version above OREO.

However seems like the docs suggests it is better to declare them in AndroidManifest for that activity instead:

When using the Window flag during activity startup, there may not be time 
to add it before the system stops your activity for being behind the 
lock-screen. This leads to a double life-cycle as it is then restarted.

For me, instead of adding the flags programmatically, adding them in AndroidManifest is cleaner anyway, and it works well in my testing

<activity
            android:name=".IncomingCallActivity"
            android:showForAllUsers="true"
            android:showWhenLocked="true"
            android:turnScreenOn="true"
            android:theme="@style/AppTheme" />

Not sure if showForAllUsers is needed, but I read somewhere that it is better to include it.

Methylnaphthalene answered 14/6, 2022 at 0:44 Comment(0)
I
0

For me, what helped was Ranjith Kumar's answer in this question.

Below is the same code, in Java:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
    // For newer than Android Oreo: call setShowWhenLocked, setTurnScreenOn
    setShowWhenLocked(true);
    setTurnScreenOn(true);

    // If you want to display the keyguard to prompt the user to unlock the phone:
    KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
    keyguardManager.requestDismissKeyguard(this, null);
} else {
    // For older versions, do it as you did before.
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
Ignazio answered 6/6, 2020 at 21:30 Comment(4)
Where do you set this?Noheminoil
I have this in the Activity's onCreate() method, @NoheminoilIgnazio
How does this work. In my case, I am throwing a notification with full screen intent from a background service. The notification sits there but the activity does not launch until I unlock the device and actually click on the notification. Can you show how are you declaring this activity on the manifestCaste
@Dibzmania, nothing special about the Activity in the manifest. It's declared as any other activity. The manifest has the USE_FULL_SCREEN_INTENT and DISABLE_KEYGUARD permissions though. Long time since I worked on that code. But take a deeper look in the code where you create the notification (e.g. use setFullScreenIntent, etc.). Good luck!Ignazio
S
0

I also had a similar issue, for me the problem was not with window Flags but when triggering notification both the notification channel should have IMPORTANCE_HIGH and notification with HIGH_PRIORITY and also of you are using redmi you have to set permission explicitly on app settings

Swayne answered 2/10, 2021 at 11:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.