是否有可能跟踪应用程序何时进入“Doze on the Go”(AKA Doze Light,Doze Extended和Doze 2)?

时间:2016-09-13 21:05:28

标签: android android-7.0-nougat android-doze android-doze-and-standby

在Android“N”中,Doze已扩展为“Doze on the Go”。

我正在寻找一种方法来检测设备何时进入并离开这些新的灯打瞌睡IDLE和IDLE_MAINTENANCE状态。 (基本上与常规的Doze here相同的问题。)

2 个答案:

答案 0 :(得分:3)

PowerManager的在线文档没有提到它,但是最新的源代码(API 24修订版1)看起来应该是这个问题的解决方案:

String ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED
        = "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED"
boolean isLightDeviceIdleMode()

理论上,您可以简单地将一些代码注册为intent的接收器并检查函数的当前值。一些人用dumpsys activity broadcasts进行探讨表明,当灯光打瞌睡状态发生变化时,意图确实被发送了。

然而,最新的SDK平台(API 24修订版2)中没有这些符号 - 我收到编译错误(有些javapjar显示它们确实不是' t present)。与Google联系,我们被告知这是预期的设计。

有一种解决方法,即对上面提到的相同字符串进行硬编码,然后使用反射来调用在API中调用的相同函数。像这样:

/**
 * Check if the device is currently in the Light IDLE mode.
 *
 * @param context The application context.
 * @return True if the device is in the Light IDLE mode.
 */
public static boolean isLightDeviceIdleMode(final Context context) {
    boolean result = false;
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    if (pm != null) {
        // result = pm.isLightDeviceIdleMode();
        try {
            Log.d(TAG, "Trying reflection for isLightDeviceIdleMode");
            Field pmServiceField = pm.getClass().getDeclaredField("mService");
            pmServiceField.setAccessible(true);
            Object pmService = pmServiceField.get(pm);

            Method isLightDeviceIdleMode = pmService.getClass().getDeclaredMethod("isLightDeviceIdleMode");
            isLightDeviceIdleMode.setAccessible(true);
            result = (Boolean) isLightDeviceIdleMode.invoke(pmService);
        } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            Log.e(TAG, "Reflection failed for isLightDeviceIdleMode: " + e.toString());
        } catch (RemoteException re) {
            Log.e(TAG, "Remote exception checking isLightDeviceIdleMode: " + e.toString());
        }
    }
    return result;
}

答案 1 :(得分:2)

TrevorWiley的回答有效,但可以简化一下。是的,Nougat的PowerManager有isLightDeviceIdleMode(),并注明@hide。我们可以使用反射来调用它,它更简洁,独立于PowerManager的内部实现细节。

public static boolean isLightDeviceIdleMode(final Context context) {
    boolean result = false;
    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    if (pm != null) {
        try {
            Method isLightDeviceIdleModeMethod = pm.getClass().getDeclaredMethod("isLightDeviceIdleMode");
            result = (boolean)isLightDeviceIdleModeMethod.invoke(pm);
        } catch (IllegalAccessException | InvocationTargetException  | NoSuchMethodException e) {
            Log.e(TAG, "Reflection failed for isLightDeviceIdleMode: " + e.toString(), e);
        }
    }
    return result;
}

主要同意TrevorWiley使用String来注册广播。与上述方法相同,您可以使用反射来获取字段ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED的值并回退到硬编码字符串"android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED"