Solution 1:

Based on some testing, using a Nexus 5 with the the final(?) preview of Android 6.0 installed:

  • Holding a PARTIAL_WAKE_LOCK is insufficient to block Doze mode — the device will still doze, even though you have the WakeLock and are trying to do regular work (e.g., setExactAndAllowWhileIdle() to get control every minute)

  • Keeping the screen on using android:keepScreenOn (or the Java equivalent), with the screen on, is sufficient to block Doze mode

  • Keeping the screen on using android:keepScreenOn (or the Java equivalent), with the screen off (user presses POWER button), is insufficient to block Doze mode

IOW, video players and the like should not be affected while the user is watching the video, even though the player may not be moving or charging. However, if the user presses the POWER button, you're back into having Doze risk.

I have not tried using FULL_WAKE_LOCK (I would expect behavior identical to android:keepScreenOn, but I am far from certain).

Solution 2:

Interesting

Google's own clock app in Android 6.0 is able to block Doze mode altogether:

  1. In the clock app set an alarm with a time < 60 minutes from now
  2. Turn off the device
  3. In the console set $adb shell dumpsys battery unplug
  4. In the console set $adb shell dumpsys deviceidle step

The state remains as 'Stepped to: ACTIVE'

If you set an alarm with a time > 60 minutes from now, it works normally (device may go into idle states). BUT once the alarm is < 60 min away it seems that the device quietly awakes from Doze idle, as the state returns 'ACTIVE' again (instead of 'IDLE_MAINTENANCE').

I really wonder how they are doing this!

- EDIT -

It seems to be setAlarmClock() that is having this behavior by default. This might be helpful for some use cases.

Solution 3:

In response to the comment discussion above, this is not an answer to the question. It's meant to clarify app behaviour in Doze mode in general. In my testing app, I tried to get a GPS position every 2 minutes, GPS signal strength was sufficient at all times.

Testing conditions:

  • Nexus 9, Android M Preview, Build MPA44I
  • "ignore optimizations" ON
  • setExactAndAllowWhileIdle() with 2 minute interval
  • each operation has a 1 minute timeout for getting a GPS fix and is surrounded by a partial wakelock
  • logs were written to SQLiteOpenHelper.getWritableDatabase()

GPS test log for Doze mode:

1   2015-09-04 - 12:14  GPS ok (device left stationary unplugged)
2   2015-09-04 - 12:16  GPS ok
3   2015-09-04 - 12:18  GPS ok
4   2015-09-04 - 12:20  GPS ok
5   2015-09-04 - 12:22  GPS ok
6   2015-09-04 - 12:24  GPS ok
7   2015-09-04 - 12:26  GPS ok
8   2015-09-04 - 12:28  GPS ok
9   2015-09-04 - 12:30  GPS ok
10  2015-09-04 - 12:32  GPS ok
11  2015-09-04 - 12:34  GPS ok
...
31  2015-09-04 - 13:14  GPS ok
32  2015-09-04 - 13:16  GPS ok
33  2015-09-04 - 13:18  GPS ok
34  2015-09-04 - 13:20  GPS ok
35  2015-09-04 - 13:22  GPS ok
36  2015-09-04 - 13:24  GPS ok
37  2015-09-04 - 13:26  GPS ok (entering Doze mode some time after)
38  2015-09-04 - 13:42  GPS failed, active millis: 60174 (idle)
39  2015-09-04 - 13:57  GPS failed, active millis: 60128 (idle)
40  2015-09-04 - 14:12  GPS failed, active millis: 60122 (idle)
41  2015-09-04 - 14:16  GPS ok (idle maintenance)
42  2015-09-04 - 14:18  GPS ok (idle maintenance)
43  2015-09-04 - 14:20  GPS ok (idle maintenance)
44  2015-09-04 - 14:22  GPS ok (idle maintenance)
45  2015-09-04 - 14:38  GPS failed, active millis: 60143 (idle)
46  2015-09-04 - 14:53  GPS failed, active millis: 60122 (idle)
47  2015-09-04 - 15:08  GPS failed, active millis: 60068 (idle)
48  2015-09-04 - 15:23  GPS failed, active millis: 60138 (idle)
49  2015-09-04 - 15:38  GPS failed, active millis: 60140 (idle)
50  2015-09-04 - 15:53  GPS failed, active millis: 60131 (idle)
51  2015-09-04 - 16:08  GPS failed, active millis: 60185 (idle)
52  2015-09-04 - 16:12  GPS ok (ending Doze mode - power button on)

Now that I looked at my logs again, I noticed a very strange behavior: The same test with "ignore optimizations" OFF showed basically identical results (like it should), BUT most of the times the timeout did not work as expected, I got 'active millis' in the range of either ~330000 (~5 times timeout time) or even ~580000 (~10 times timeout time) while idle. This weird behavior I can not explain, but it seems to show that there actually IS some effect of the setting of "ignore optimizations" on Doze mode.

Edit: The 'strange' behavior described above is just now documented: Only with "ignore optimizations" ON, you may hold a partial wakelock in Doze idle mode.