How to make Alarm Manager work when Android 6.0 in Doze mode?
Asked Answered
A

2

54

I am a developer of two alarm clock apps on Google Play. I am trying to get them to work with Android 6.0. However, Doze mode makes it so they do not ring. I put them on the white list, I put a foreground notification icon up, I'm not sure what else I can do - when in Doze mode, the the Alarm Manager alarms are still ignored. The Clock app (which is a Google Play rather than AOSP app), however, is different. When the alarm is enabled on the Clock app, "adb deviceidle step" will always read "active" and never "idle", "idle_pending" or anything else.

Is Android cheating here, giving its own app more power, aka. "pulling an apple"? Are all alarm clock apps on Google Play about to become non-functional? Kind of worried here, these are quality apps that each took a year of part-time development time, and are big income sources for me. Any clues on how I could get these to work would be a huge help.

Setting the AlarmManager intent:

        Intent intent = new Intent(context, ReceiverAlarm.class);
        if (android.os.Build.VERSION.SDK_INT >= 16) {
            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        }
        amSender = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_CANCEL_CURRENT); //FLAG_CANCEL_CURRENT seems to be required to prevent a bug where the intent doesn't fire after app reinstall in KitKat
        am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        am.set(AlarmManager.RTC_WAKEUP, scheduleToTime+1, amSender);

and the ReceiverAlarm class:

public class ReceiverAlarm extends BroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent) {
    if (wakeLock == null) {
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Theme.appTitle);
        wakeLock.acquire();
    }
    X.alarmMaster.startRingingAlarm(true);
}

and the relevant parts of the X.alarmMaster.startRingingAlarm() method:

    if (wakeLock == null) {
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Theme.appTitle);
        wakeLock.acquire();
    }

    if (screenWakeLock == null) {
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        screenWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, Theme.appTitle+" scr");
        screenWakeLock.acquire();
    }

    Intent alarmIntent = new Intent(Intent.ACTION_VIEW);
    alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    alarmIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    alarmIntent.setClass(context, ActivityAlarmAlarm.class);

    context.startActivity(alarmIntent);

Some of the methods have been pasted inline for easier readability.

Athens answered 10/9, 2015 at 3:41 Comment(3)
Lets have some snippets that can help others see what is going on. Please :-)Knobloch
Sure, I'll edit my response. They are both 20k+ lines of code, so I'll try to post the relevant lines for one of them.Athens
Interesting, any help on that one ? alarm clocks riddleGuttersnipe
B
38

Doze and App Standby definitely change the behavior in regards to alarms and wakelocks, but they're definitely not the end of the world for you!

Have you tried using the method setAlarmclock() instead of set()? It's designed specifically for alarm clocks and may be able to cut through doze. There are a few adb commands you can use to manually put a phone into doze or app standby mode: https://developer.android.com/preview/features/power-mgmt.html

If that isn't able to wake your app up, there's the surefire method setExactAndAllowWhileIdle() is designed to wake the phone from doze no matter what. Worst case scenario, you can wake your app up with this method and use the wakeup to schedule the next alarm.

Another page worth a read is this blog post with its flowchart for background work and alarms: https://plus.google.com/+AndroidDevelopers/posts/GdNrQciPwqo

Bonnes answered 10/9, 2015 at 20:59 Comment(11)
this appears to be working, using setAlarmClock(). when I try to set my app into doze mode using "adb shell deviceidle step", and the alarm will be ringing soon, it will keep the mode in ACTIVE.Athens
This is helpful! But see this report code.google.com/p/android-developer-preview/issues/… that the set[Exact]AndAllowWhileIdle() methods don't work. :-(Trustee
In plus.google.com/+AndroidDevelopers/posts/94jCkmG4jff Ian Lake reports that in internal builds, the AndAllowWhileIdle() methods fire during Doze much more as you'd expect compared to Developer Preview 3.Trustee
From my tests using Developer Preview 3 and both the setExactAndAllowWhileIdle() and setAndAllowWhileIdle() methods, those alarms will trigger during an idle state for a duration of about 10 seconds of network connectivity. Additionally, they may only be called a minimum of 15 minutes apart. However, the phone never technically comes out of idle mode during this period. setAlarmClock() seems to wake the entire phone out of idle mode, and allows for a much longer wakelock.Bonnes
@black Have you tested it yet? I'm not sure about what you said because this(developer.android.com/reference/android/app/AlarmManager.html) still says '15 minutes' thing, whereas this(developer.android.com/training/monitoring-device-state/…) mentions '9 minutes'..Gonzalez
@Gonzalez I think I checked the source code actually. But this is AOSP so an OEM can change it to whatever it wants probably.Wieldy
@Wieldy I see.. In fact, one developer I know said he recently tested this on his device Samsung Galaxy S7 and it took longer than 10 minutes. That's why I asked you. Thanks!Gonzalez
@Bonnes What if we need to implement alarmManager.setRepeating() in the doze mode? Can we implement that?Guillen
The biggest issue with setAlarmClock() is that it is visible to the user: The user will see the alarm clock icon in their status bar, as if they had set an alarm with their device's built-in alarm clock app The user will see the time of the alarm when they fully slide open their notification shadePreconception
The link to G+ post is now deadInterference
#32627842Gora
A
3

Put the application in whitelist only allows network in doze mode. AlarmManager does not affected by whitelist.

For setExactAndAllowWhileIdle() method please check the below description from SDK. It will not wake the phone from doze.

When the alarm is dispatched, the app will also be added to the system's temporary whitelist for approximately 10 seconds to allow that application to acquire further wake locks in which to complete its work.

Almaraz answered 15/9, 2015 at 12:27 Comment(4)
That's right. From the docs : " The whitelisted app’s jobs and syncs are deferred, and its regular AlarmManager alarms do not fire."Pained
@UncaughtException so how can I handle this today for android 6 and 7? Can you provide any example of implementation?Discommon
please share if you found any solutionBreakfast
#32627842Gora

© 2022 - 2024 — McMap. All rights reserved.