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.

cuihtlauac
  • 1,808
  • 2
  • 20
  • 39
user1908060
  • 683
  • 1
  • 6
  • 8
  • Lets have some snippets that can help others see what is going on. Please :-) – Nabin Sep 10 '15 at 03:46
  • 1
    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. – user1908060 Sep 10 '15 at 04:01
  • Interesting, any help on that one ? [alarm clocks riddle](https://stackoverflow.com/questions/53869043/multiple-cell-phone-alarms-which-one-covers-the-other-which-alarm-is-preceded) – Old Ben Murphy Dec 21 '18 at 13:31

2 Answers2

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

serv-inc
  • 35,772
  • 9
  • 166
  • 188
ccpmark
  • 1,005
  • 1
  • 10
  • 11
  • 6
    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. – user1908060 Sep 12 '15 at 23:37
  • 4
    This is helpful! But see this report https://code.google.com/p/android-developer-preview/issues/detail?id=2225 that the `set[Exact]AndAllowWhileIdle()` methods don't work. :-( – Jerry101 Sep 22 '15 at 08:45
  • In https://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. – Jerry101 Sep 22 '15 at 22:20
  • 4
    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. – ccpmark Sep 23 '15 at 03:25
  • @black Have you tested it yet? I'm not sure about what you said because this(https://developer.android.com/reference/android/app/AlarmManager.html) still says '15 minutes' thing, whereas this(https://developer.android.com/training/monitoring-device-state/doze-standby.html) mentions '9 minutes'.. – Jenix Jun 24 '17 at 19:05
  • 1
    @Jenix I think I checked the source code actually. But this is AOSP so an OEM can change it to whatever it wants probably. – black Jun 25 '17 at 20:51
  • @black 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! – Jenix Jun 26 '17 at 11:02
  • @ccpmark What if we need to implement alarmManager.setRepeating() in the doze mode? Can we implement that? – devgeek Sep 08 '17 at 12:26
  • 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 shade – Hossam Hassan Nov 26 '18 at 09:46
  • The link to G+ post is now dead – Vadim Kotov Oct 31 '19 at 12:07
  • https://stackoverflow.com/questions/32627342/how-to-whitelist-app-in-doze-mode-android-6-0 – aliep Mar 08 '21 at 20:31
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.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Wonil
  • 6,364
  • 2
  • 37
  • 55