Android-job: Alarm gone after swiping an app from recent apps

Created on 7 Jan 2017  路  19Comments  路  Source: evernote/android-job

On my device(LeTv One/Android 6):

  1. I scheduling new job
  2. check active alarms via adb shell dumpsys alarm
  3. see such intents:
Batch{7fae56f num=1 leuiTimeAlign=false start=1483824064305 end=1483824064305}:
    RTC_WAKEUP #0: Alarm{a95b27c type 0 when 2967563176917 red.kometa.steelsunset}
      tag=*walarm*:red.kometa.steelsunset/com.evernote.android.job.v14.PlatformAlarmReceiver
      type=0 whenElapsed=+17173d9h41m15s838ms when=2064-01-14 22:06:16
      window=0 repeatInterval=0 count=0 flags=0x0
      operation=PendingIntent{edbf82e: PendingIntentRecord{cedbf73 red.kometa.steelsunset broadcastIntent key.isShadow:false}}
Batch{606f705 num=1 leuiTimeAlign=false start=1483841004908 end=1483841004908}:
    RTC_WAKEUP #0: Alarm{318e35a type 0 when 2967580117519 red.kometa.steelsunset}
      tag=*walarm*:red.kometa.steelsunset/com.evernote.android.job.v14.PlatformAlarmReceiver
      type=0 whenElapsed=+17173d14h23m36s441ms when=2064-01-15 02:48:37
      window=0 repeatInterval=0 count=0 flags=0x0
      operation=PendingIntent{db939e0: PendingIntentRecord{ff45b9d red.kometa.steelsunset broadcastIntent key.isShadow:false}}
  1. close app via swiping it from recent apps
  2. check active alarms via adb shell dumpsys alarm
  3. scheduled Intents are gone

The same situation with AlarmManager: stackoverflow

Some other apps from google play schedule their notifications without any problems. What's the trick? Is it expected behavior?

help wanted

Most helpful comment

I would like to comment and say this - I've tried to schedule a Service class using Android's AlarmManager but it failed miserably.

After switching for a Service to a BroadcastReceiver it did work. I'm not sure what's the specific reason but I want to think that maybe the service is running in the background and therefore AlarmManager doesn't start another instance of the service.

Here's my current, working, code -

        Intent serviceIntent = new Intent(this, <BroadcastReceiver>.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, serviceIntent, 0);
        AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000*60, pendingIntent);

This will send a broadcast every minute.

All 19 comments

Good find. That's actually expected behavior and I don't know any way to prevent this issue. My assumption is that Google thinks that when the user swipes away the app, then he doesn't want to use it anymore and even cancels all alarms (it's like a force close). The next time the app starts it's possible to reschedule alarms and that's what this library does: https://github.com/evernote/android-job/blob/master/library/src/main/java/com/evernote/android/job/JobManager.java#L482

So your jobs aren't lost.

Simple project that reproduces this behavior with AlarmManager: https://github.com/Try4W/AlarmManagerDemo

The next time the app starts it's possible to reschedule alarms

But what should I do if my application is "alarm clock"? One of the possible ways is to add my app to 'whitelist'(protected apps).

There is an app on my phone: My Therapy. It shows notification every evening even if app is swiped out from recent without being marked as 'protected app'.
I tried to decompile it's apk, but I can't find anything special in scheduling their alarms.

Note: alarms scheduled by BroadcastReciever on ACTION_BOOT_COMPLETED works okay until I open and 'force-close' my application

I don't know. That's not a problem of this library but a general issue with the AlarmManager. You could more broadcasts to your manifest so that you app is started again, but that's also a bad approach.

Note 2: even after force-stopping app via swiping it from recent apps this expression:
PendingIntent.getBroadcast(context, REQUEST_CODE, notificationIntent, PendingIntent.FLAG_NO_CREATE) != null (explanation)
returns true

Can you post the full code how you created the PendingIntent? I'd like to try it myself.

Okay, I tried it myself again with following snippet and I couldn't reproduce what you mentioned.

Intent intent = new Intent(this, PlatformAlarmReceiver.class);

// will be null after force closing or swiping away
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 4, intent, PendingIntent.FLAG_NO_CREATE);

pendingIntent = PendingIntent.getBroadcast(this, 4, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
manager.set(AlarmManager.RTC, System.currentTimeMillis() + TimeUnit.HOURS.toMillis(30), pendingIntent);

I will provide sources and video demonstration within a few days.

There is some code in Kotlin:

    companion object {
        const val REQUEST_CODE = 3434
    }

    fun schedulePendingIntent(triggerTimeMillis: Long, pendingIntent: PendingIntent) {
        if (Build.VERSION.SDK_INT >= 23) { // https://stackoverflow.com/questions/34378707/alarm-manager-does-not-work-in-background-on-android-6-0
            logger.debug("setExactAndAllowWhileIdle")
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTimeMillis, pendingIntent)
        } else {
            if (Build.VERSION.SDK_INT >= 19) {
                logger.debug("setExact")
                alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTimeMillis, pendingIntent)
            } else {
                logger.debug("set")
                alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTimeMillis, pendingIntent)
            }
        }
    }

    fun checkAlarmScheduled(): Boolean {
        val notificationIntent = Intent(BringUserBackAppReminder.ACTION_FIRE_NOTIFICATION)
        return PendingIntent.getBroadcast(context, REQUEST_CODE, notificationIntent, PendingIntent.FLAG_NO_CREATE) != null
    }

    private fun getNotificationPendingIntent(): PendingIntent {
        val notificationIntent = Intent(BringUserBackAppReminder.ACTION_FIRE_NOTIFICATION)
        return PendingIntent.getBroadcast(context, REQUEST_CODE, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT)
    }

(sorry for the mistakes, English is not my native language)

Note 2: even after force-stopping app via swiping it from recent apps this expression:
PendingIntent.getBroadcast(context, REQUEST_CODE, notificationIntent, PendingIntent.FLAG_NO_CREATE) != null (explanation)
returns true

I can reproduce this bug on my device. I can't stream my phone screen on my pc and I can't make a clear video demonstration.

Here is updated demo project: https://github.com/Try4W/AlarmManagerDemo

How to reproduce:
Listen to ACTION_POWER_CONNECTED action:

        <receiver android:name=".PowerConnectedBroadcastReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
            </intent-filter>
        </receiver>

In this demo I just print PendingIntent.getBroadcast(...) != null result in console:

public class PowerConnectedBroadcastReceiver extends BroadcastReceiver {

    private static final String TAG = "PowerConnectedBroRe";

    @Override
    public void onReceive(Context context, Intent intent) {
        AlarmHelper alarmManager = new AlarmHelper(context);
        Log.d(TAG, "PendingIntent.getBroadcast(...) != null: " + alarmManager.isAlarmScheduled());
    }
}

And there is the problem. If you swipe an app from recent apps and try to call alarmManager.isAlarmScheduled() after starting an application from 'apps menu' it will return FALSE.

If you will try to call the same method from PowerConnectedBroadcastReceiver(via connecting your phone to pc via USB) after swiping an app from recent apps it will return TRUE.
And if then you launch your application again, you will see that alarmManager.isAlarmScheduled() still returns TRUE even if there is no scheduled alarm in adb shell dumpsys alarm output.

I tried your test application and cannot reproduce what you've explained (Nexus 6P). My log

D/TTTTT: PendingIntent.getBroadcast(...) != null: false // started app
D/TTTTT: PendingIntent.getBroadcast(...) != null: true // scheduled alarm, swiped app away, reconnected device to PC
D/TTTTT: PendingIntent.getBroadcast(...) != null: true // from the broadcast receiver
D/TTTTT: PendingIntent.getBroadcast(...) != null: true // started app
D/TTTTT: PendingIntent.getBroadcast(...) != null: false // canceled alarm, swiped app away, reconnected device to PC
D/TTTTT: PendingIntent.getBroadcast(...) != null: false // from the broadcast receiver
D/TTTTT: PendingIntent.getBroadcast(...) != null: false // started app

Everything works as expected.

I describe the same behavior. It looks right, but you missing the problem:

If you will try to call the same method from PowerConnectedBroadcastReceiver(via connecting your phone to pc via USB) after swiping an app from recent apps it will return TRUE.
And if then you launch your application again, you will see that alarmManager.isAlarmScheduled() still returns TRUE even if there is no scheduled alarm in adb shell dumpsys alarm output.

PendingIntent.getBroadcast(...) != null shouldn't return true if you swipe away demo application('force close' it).
Can you reproduce the problem described in the first issue's message?
If so, try to list your alarms with adb shell dumpsys alarm after 'force stop' demo application.
If there is no Intent in the list, how can PendingIntent.getBroadcast(...) != null return true?

Ah, yes, I missed that. But after swiping the app away adb shell dumpsys alarm still returns the PendingIntent for me. So PendingIntent.getBroadcast() is consistent with the output.

But I'm not sure right now why the alarm isn't cleared after swiping the app away. However, force closing the app definitely clears the alarm.

Yeah, It looks like this problem is partly in my rom. LeTv One runs on EUI. But the same behavior is seen on different roms with their own 'optimizers'.

And some developers find a workaround for this issue.

I managed to get a response from the developers of Bookmate's android application. They use GCM for pushing notifications. But it doesn't work without an internet connection and moreover, can't be applied to your library.

Of course, that issue is specific to the AlarmManager. This library is using the JobScheduler and GcmNetworkManager if possible. The AlarmManager is only a fallback if the other two aren't available (exact jobs require the AlarmManager).

Closing because of inactivity. Feel free to reply nonetheless.

Did you consider using a Foreground Service to solve you issue?

it's late but i hope someone will get help from this.
Recently i have worked on an android project based on schedule alarm.I faced the same problem and got it working by stopping the debugger and running the app from the device.
(sorry for my bad english)

I would like to comment and say this - I've tried to schedule a Service class using Android's AlarmManager but it failed miserably.

After switching for a Service to a BroadcastReceiver it did work. I'm not sure what's the specific reason but I want to think that maybe the service is running in the background and therefore AlarmManager doesn't start another instance of the service.

Here's my current, working, code -

        Intent serviceIntent = new Intent(this, <BroadcastReceiver>.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, serviceIntent, 0);
        AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        alarm.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000*60, pendingIntent);

This will send a broadcast every minute.

@tsirolnik you're absolutely right.

This is because of Android Background limitation:

Background start not allowed: service Intent ...

More info here: https://stackoverflow.com/questions/45016174/android-o-and-background-limits-prevents-simple-alarm-notification

Say, I have a similar issue with AlarmManager.
On Pixel 4 (or emulator) with Android 10 (or 11), I schedule it, remove from recent tasks and then it never gets triggered.
How come? I reported about this to Google because to me it seems like a bug:

https://issuetracker.google.com/issues/149556385

But as opposed to what's written here, I don't directly open a service, but open a broadcast receiver instead.

I've read the entire post, and I still don't get how to fix it. Can anyone helpe?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

georgikoemdzhiev picture georgikoemdzhiev  路  4Comments

letos picture letos  路  4Comments

jsu4650 picture jsu4650  路  5Comments

anukools picture anukools  路  7Comments

vibin picture vibin  路  3Comments