Можно ли отследить, когда приложение входит в режим Doze on the Go (также известный как Doze Light, Doze Extended и Doze 2)?

В Android "N" функция Doze была дополнена "Doze on вперед".

Я ищу способ определить, когда устройство входит и выходит из этих новых состояний IDLE и IDLE_MAINTENANCE легкой дремоты. (В основном тот же вопрос, который был задан для обычного Doze здесь.)


person TrevorWiley    schedule 13.09.2016    source источник


Ответы (2)


Реализация в ответе TrevorWiley работает, но ее можно немного упростить. Да, PowerManager Nougat имеет 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".

person ksparrow    schedule 16.06.2017
comment
Я больше не делаю ничего, связанного с Android, поэтому не могу проверить, работает ли это, но это выглядит разумно, поэтому я переключаю это на принятый ответ. Если у кого-то возникнут проблемы с этим, они всегда могут вернуться к моему ответу. - person TrevorWiley; 18.06.2017

В онлайн-документации для 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) этих символов нет - я получаю ошибки компиляции (и некоторые тычки с 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;
}
person TrevorWiley    schedule 15.09.2016
comment
См. code.google.com/p/android/issues/detail?id. =222595 за расследование пропажи API. - person TrevorWiley; 15.09.2016
comment
Мы связались с Google в автономном режиме, поэтому проблема, упомянутая в моем последнем комментарии, в настоящее время не содержит официального ответа. - person TrevorWiley; 22.09.2016