【问题标题】:Is it possible to track when an app enters "Doze on the Go" (AKA Doze Light, Doze Extended, and Doze 2)?是否可以跟踪应用程序何时进入“Doze on the Go”(AKA Doze Light、Doze Extended 和 Doze 2)?
【发布时间】:2016-09-13 21:05:27
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

    PowerManager 的在线文档没有提到它,但最新的源代码(API 24 修订版 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)中没有这些符号 - 我收到编译错误(有些戳 javapjar 表明它们确实不存在)。联系 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;
    }
    

    【讨论】:

    【解决方案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 使用字符串来注册广播。和上面的方法一样,你可以使用反射来获取字段ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED的值,然后回退到硬编码的字符串"android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED"

    【讨论】:

    • 我不再做任何与 Android 相关的事情,所以我无法验证它是否有效,但它看起来很合理,所以我将其切换为接受的答案。如果有人遇到问题,他们总是可以回到我的答案。
    猜你喜欢
    • 2016-08-22
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2023-03-15
    • 1970-01-01
    • 2015-11-07
    • 1970-01-01
    相关资源
    最近更新 更多