是否可以跟踪应用何时进入 "Doze on the Go"(又名 Doze Light、Doze Extended 和 Doze 2)?
Is it possible to track when an app enters "Doze on the Go" (AKA Doze Light, Doze Extended, and Doze 2)?
在 Android "N" 中,Doze 已扩展为“Doze on the Go”。
我正在寻找一种方法来检测设备何时进入和离开这些新的轻度睡眠 IDLE 和 IDLE_MAINTENANCE 状态。 (基本上与常规打瞌睡 所问的相同问题。)
PowerManager的在线文档没有提到,但最新的源代码(API 24 revision 1)看起来应该是这个问题的解决方案:
String ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED
= "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED"
boolean isLightDeviceIdleMode()
理论上,您可以简单地注册一些代码作为意图的接收者并检查函数的当前值。一些探索 dumpsys activity broadcasts
表明当轻度打瞌睡状态改变时确实发送了意图。
但是,最新的 SDK 平台(API 24 修订版 2)中没有这些符号 - 我遇到编译错误(还有一些 javap
和 jar
表明他们真的不存在)。联系 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;
}
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 使用字符串注册广播。与上述方法相同,您可以使用反射来获取字段 ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED
的值并回退到硬编码的 String "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED"
.
在 Android "N" 中,Doze 已扩展为“Doze on the Go”。
我正在寻找一种方法来检测设备何时进入和离开这些新的轻度睡眠 IDLE 和 IDLE_MAINTENANCE 状态。 (基本上与常规打瞌睡
PowerManager的在线文档没有提到,但最新的源代码(API 24 revision 1)看起来应该是这个问题的解决方案:
String ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED
= "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED"
boolean isLightDeviceIdleMode()
理论上,您可以简单地注册一些代码作为意图的接收者并检查函数的当前值。一些探索 dumpsys activity broadcasts
表明当轻度打瞌睡状态改变时确实发送了意图。
但是,最新的 SDK 平台(API 24 修订版 2)中没有这些符号 - 我遇到编译错误(还有一些 javap
和 jar
表明他们真的不存在)。联系 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;
}
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 使用字符串注册广播。与上述方法相同,您可以使用反射来获取字段 ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED
的值并回退到硬编码的 String "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED"
.