Search code examples
androidandroid-intentbroadcastreceiverandroid-notificationsandroid-pendingintent

Is it possible to start backgroung app when the screen is turned off ? How?


Is it possible to start a background app when a broadcast receiver is activated and the screen is off ? I am not running any service in background just want to wake up and unlock the screen and show an activity from an app that is in the background. At the moment I am able to wake up and unlock the screen only if the app was in foreground when the screen turned off.


Solution

  • After a bit of searching and hair pulling it turns out there are a few things that really matter when one wants to have an activity shown directly above the lockscreen (or better said unlock and show the activity).

    When creating a channel (for android 8+) one needs to define the visibility of the channel as: channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); this will show it above the lock screen.

    Also the notification needs to have proper visibility like: .setVisibility(NotificationCompat.VISIBILITY_PUBLIC). But to actually start the activity you need to set the fullscreenIntent: builder.setFullScreenIntent(pendingI, true);

    If needed and the notification is important and if you need the above then you have very big chances you also need the priotity set: .setVisibility(NotificationCompat.VISIBILITY_PUBLIC).

    See the below code examples...

    requestCode = 587;
    NOTIFICATION_ID = 111;
    private void launchFullScreenNotification(Intent activityIntent) {
        PendingIntent pendingI = PendingIntent.getActivity(mContext.getApplicationContext(),
                requestCode, intentTinta, PendingIntent.FLAG_UPDATE_CURRENT);
    
        NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, CHANNEL_ID)
                .setLights(Color.WHITE, 2000, 3000)
                .setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
                .setSmallIcon(android.R.drawable.arrow_up_float)
                .setContentTitle("blink blink")
                .setContentText("check me out...")
                // this is important...
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setCategory(NotificationCompat.CATEGORY_ALARM)
                // this is important...
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setAutoCancel(true);
    
        // very important, this is the activity intent to launch automatically
        builder.setFullScreenIntent(pendingI, true);
        Notification incomingCallNotification = builder.build();
    
        NotificationManagerCompat notifMan = NotificationManagerCompat.from(mContext);
        notifMan.notify(NOTIFICATION_ID, incomingCallNotification);
    
        PowerManager powerManager = (PowerManager) mContext.getSystemService(POWER_SERVICE);
    
        if (!powerManager.isInteractive()) { // if screen is not already on, turn it on
            PowerManager.WakeLock wl = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "alarma:SCREENLOCK");
            wl.acquire(60000);
            PowerManager.WakeLock wl_cpu = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "alarma:SCREENLOCK");
            wl_cpu.acquire(60000);
        }
    }
    
    private void createChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mChannel = new NotificationChannel(CHANNEL_ID, channel_name, NotificationManager.IMPORTANCE_HIGH);
    
            // Configure the notification channel.
            mChannel.setDescription(channel_description);
            mChannel.enableLights(true);
            // Sets the notification light color for notifications posted to this
            // channel, if the device supports this feature.
            mChannel.setLightColor(Color.RED);
            mChannel.enableVibration(true);
            mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                mChannel.setAllowBubbles(true);
            }
            // this is important...
            mChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
    
            NotificationManager mNotificationManager = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE);
            mNotificationManager.createNotificationChannel(mChannel);
        }
    }
    

    Also if you want the activity to be shown above the lockscreen you might be interested in adding either into the manifest something like:

    android:turnScreenOn="true"
    android:showOnLockScreen="true"
    

    Alternatively you might need to add in the onCreate method after the setContentView() something like:

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
            this.setTurnScreenOn(true);
            this.setShowWhenLocked(true);
        } else {
            final Window window = getWindow();
            window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
                    WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                    WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
                    WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                    WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
        }
    
        KeyguardManager keyguardManager=(KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE) ;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            keyguardManager.requestDismissKeyguard(this, null);
        }
    

    Since I just discovered how this code works I might discover some other things along the way so bear in mind I might update this answer after some time...