8

Can a third party application get an action once the device goes in to Doze mode?

Trying to register Broadcast receiver for below action,

<receiver android:name="com.doze.sample.DozemodeReceiver" android:enabled="true">
    <intent-filter>
        <action android:name=" android.os.action.DEVICE_IDLE_MODE_CHANGED" />
    </intent-filter>
</receiver>

It's not working (the receiver is not being called).

zmarties
  • 4,809
  • 22
  • 39
Rupali
  • 774
  • 7
  • 15

2 Answers2

17

Building on a perfect answer provided by @zmarties, here is the full solution:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        BroadcastReceiver receiver = new BroadcastReceiver() {
            @RequiresApi(api = Build.VERSION_CODES.M) @Override public void onReceive(Context context, Intent intent) {
                PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

                if (pm.isDeviceIdleMode()) {
                    // the device is now in doze mode
                } else {
                   // the device just woke up from doze mode
                }
            }
        };

        context.registerReceiver(receiver, new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
    }

In case you are able to check when the context is destroyed (e.g. in the activity or service), call this to avoid leaking resources:

context.unregisterReceiver(receiver);

To test this piece of code, use the following commands:

adb shell dumpsys deviceidle force-idle

to bring the device into doze mode,

adb shell dumpsys deviceidle step

To wake up the device from Doze.

vanomart
  • 1,739
  • 1
  • 18
  • 39
  • 1
    I am using exactly the same method for catching that broadcast but it seems to be working only when I invoke deviceidle force-idle and unforce. If I leave my phone standing for over an hour without touching it, nothing gets received in my broadcast receiver. Anyone experienced this? – Sava Mikalački Mar 21 '17 at 19:34
  • same problem here – Muppet May 31 '17 at 00:31
  • 1
    @SavaMikalački: The phone is unplugged, right? That is one of the conditions for entering Doze mode. – Bob Snyder Jun 17 '17 at 21:27
  • @BobSnyder yes, my phone is disconnected. After some more tests I found out that I do get the broadcast when my phone is idle for several hours and I even get it over night when my phone is connected to my charger after several hours. Also, I understood that since there are steps when you call deviceidle step command, that I would also get these steps in the broadcast, but I only get broadcast if it went to idle and when it wakes up. – Sava Mikalački Jun 23 '17 at 08:24
  • @SavaMikalački: Thanks for the feedback. The broadcasts are similarly inconsistent for me. It's disappointing. I was expecting they would be a more reliable indication of idle state changes. – Bob Snyder Jun 23 '17 at 12:48
  • Is it possible to register to it in manifest instead? Also, when entering this state, does it mean mobile data cannot be used? – android developer Aug 30 '17 at 12:02
  • @BobSnyder There are several stages of idle mode. Light Doze, Deep Doze, and each has several states. It takes a while to enter Deep Doze. [(click here for article)](https://medium.com/@mohitgupta_87777/testing-your-app-on-doze-mode-4ee30ad6a3b0) You may also have active wakelocks preventing the phone from entering idle mode. – paperduck Sep 22 '17 at 00:25
  • Based on [the android documentation for testing your app with Doze](https://developer.android.com/training/monitoring-device-state/doze-standby#testing_doze), you should use `adb shell dumpsys deviceidle unforce` to wake the device from Doze, not `dupsys deviceidle step` – Nathan F. Feb 12 '20 at 21:52
14

To confirm what was mentioned in the comments, defining the android.os.action.DEVICE_IDLE_MODE_CHANGED broadcast receiver via the AndroidManifest.xml has no effect.

The only way to register the receiver is to do it dynamically:

IntentFilter filter = new IntentFilter();
filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
context.registerReceiver(new BroadcastReceiver()
{
  @Override
  public void onReceive(Context context, Intent intent)
  {
    onDeviceIdleChanged();
  }
}, filter);
zmarties
  • 4,809
  • 22
  • 39
  • 1
    remember that if you use activity context, you need to unregister the receiver, so it can't be created as an anonymous class. – vanomart Feb 06 '17 at 10:09