如何在 Android 6.0 打盹模式下将应用列入白名单

IT小君   2021-09-20T22:46:47

此问题与将于本月底最终发布的 Android 6.0 Preview 3 有关。

我正在 Nexus 5“hammerhead”上的 Google 预览版 3 中测试 Android 6.0 中的一些内容。

新功能是“打盹模式”——类似于网络禁用和手机休眠时的深度睡眠模式,只有短信、电话或高优先级 GCM 消息才能唤醒它。但就像 WhatsApp - 在打盹模式下,它会在 2 小时或更长时间后收到消息,具体取决于计时器。但是有一个名为“白名单”的“未优化”应用程序列表,您可以在其中手动添加应用程序。

好的,我想找到一种方法,无需用户交互即可以编程方式将我的应用程序添加到设备中电池设置中存在的“白名单应用程序列表”中。

尝试使用反射进入它我发现:

在 android.os.IDeviceIdleController 中有一个方法:

public abstract void addPowerSaveWhitelistApp (String packageNameOfApp)

但这是一个接口......所以我们不能制作接口的实例。

目前还没有关于这个接口、方法或任何继承树的文档。

也许你知道我应该在哪里寻找以编程方式添加我的应用程序的可能性?

还有一个方法

public abstract boolean isPowerSaveWhitelistApp (String packageName)

我认为应该可以以某种方式访问​​?!检查应用程序是否存在于白名单中,也许在最后希望要求用户将其添加到白名单中。

所以我的问题是,你们有没有人试图做出更好的结果?因为我被卡住了,我认为这是一个死胡同。

更多信息:https : //newcircle.com/s/post/1739/2015/06/12/diving-into-android-m-doze

评论(6)
IT小君

添加权限

<uses-permission 
android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

请求将您的应用列入白名单

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    Intent intent = new Intent();
    String packageName = getPackageName();
    PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
    if (!pm.isIgnoringBatteryOptimizations(packageName)) {
        intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
        intent.setData(Uri.parse("package:" + packageName));
        startActivity(intent);
    }
}
2021-09-20T22:46:48   回复
IT小君

在 Android M 预览版 3 上,如果没有用户交互,则无法禁用电池优化(= 休眠模式的白名单应用程序)。

可以通过以下方式通过用户交互来完成:

Intent intent = new Intent();
String packageName = context.getPackageName();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (pm.isIgnoringBatteryOptimizations(packageName))
    intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
else {
    intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
    intent.setData(Uri.parse("package:" + packageName));
}
context.startActivity(intent);
2021-09-20T22:46:49   回复
IT小君

我认为这个助手类应该可以满足你的所有需求。

要使用它来请求操作系统将您的应用程序列入白名单,您可以使用 prepareIntentForWhiteListingOfBatteryOptimization。如果您得到 null,则表示您不需要它,或者您不能使用它。您可以使用另一个函数来查询您所处的更好状态。

public class PowerSaverHelper {
    public enum PowerSaveState {
        ON, OFF, ERROR_GETTING_STATE, IRRELEVANT_OLD_ANDROID_API
    }

    public enum WhiteListedInBatteryOptimizations {
        WHITE_LISTED, NOT_WHITE_LISTED, ERROR_GETTING_STATE, UNKNOWN_TOO_OLD_ANDROID_API_FOR_CHECKING, IRRELEVANT_OLD_ANDROID_API
    }

    public enum DozeState {
        NORMAL_INTERACTIVE, DOZE_TURNED_ON_IDLE, NORMAL_NON_INTERACTIVE, ERROR_GETTING_STATE, IRRELEVANT_OLD_ANDROID_API, UNKNOWN_TOO_OLD_ANDROID_API_FOR_CHECKING
    }

    @NonNull
    public static DozeState getDozeState(@NonNull Context context) {
        if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)
            return DozeState.IRRELEVANT_OLD_ANDROID_API;
        if (VERSION.SDK_INT < VERSION_CODES.M) {
            return DozeState.UNKNOWN_TOO_OLD_ANDROID_API_FOR_CHECKING;
        }
        final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        if (pm == null)
            return DozeState.ERROR_GETTING_STATE;
        return pm.isDeviceIdleMode() ? DozeState.DOZE_TURNED_ON_IDLE : pm.isInteractive() ? DozeState.NORMAL_INTERACTIVE : DozeState.NORMAL_NON_INTERACTIVE;
    }

    @NonNull
    public static PowerSaveState getPowerSaveState(@NonNull Context context) {
        if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)
            return PowerSaveState.IRRELEVANT_OLD_ANDROID_API;
        final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        if (pm == null)
            return PowerSaveState.ERROR_GETTING_STATE;
        return pm.isPowerSaveMode() ? PowerSaveState.ON : PowerSaveState.OFF;
    }


    @NonNull
    public static WhiteListedInBatteryOptimizations getIfAppIsWhiteListedFromBatteryOptimizations(@NonNull Context context, @NonNull String packageName) {
        if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)
            return WhiteListedInBatteryOptimizations.IRRELEVANT_OLD_ANDROID_API;
        if (VERSION.SDK_INT < VERSION_CODES.M)
            return WhiteListedInBatteryOptimizations.UNKNOWN_TOO_OLD_ANDROID_API_FOR_CHECKING;
        final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        if (pm == null)
            return WhiteListedInBatteryOptimizations.ERROR_GETTING_STATE;
        return pm.isIgnoringBatteryOptimizations(packageName) ? WhiteListedInBatteryOptimizations.WHITE_LISTED : WhiteListedInBatteryOptimizations.NOT_WHITE_LISTED;
    }

    @TargetApi(VERSION_CODES.M)
    @RequiresPermission(permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
    @Nullable
    public static Intent prepareIntentForWhiteListingOfBatteryOptimization(@NonNull Context context, @NonNull String packageName, boolean alsoWhenWhiteListed) {
        if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP)
            return null;
        if (ContextCompat.checkSelfPermission(context, permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) == PackageManager.PERMISSION_DENIED)
            return null;
        final WhiteListedInBatteryOptimizations appIsWhiteListedFromPowerSave = getIfAppIsWhiteListedFromBatteryOptimizations(context, packageName);
        Intent intent = null;
        switch (appIsWhiteListedFromPowerSave) {
            case WHITE_LISTED:
                if (alsoWhenWhiteListed)
                    intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
                break;
            case NOT_WHITE_LISTED:
                intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).setData(Uri.parse("package:" + packageName));
                break;
            case ERROR_GETTING_STATE:
            case UNKNOWN_TOO_OLD_ANDROID_API_FOR_CHECKING:
            case IRRELEVANT_OLD_ANDROID_API:
            default:
                break;
        }
        return intent;
    }

    /**
     * registers a receiver to listen to power-save events. returns true iff succeeded to register the broadcastReceiver.
     */
    @TargetApi(VERSION_CODES.M)
    public static boolean registerPowerSaveReceiver(@NonNull Context context, @NonNull BroadcastReceiver receiver) {
        if (VERSION.SDK_INT < VERSION_CODES.M)
            return false;
        IntentFilter filter = new IntentFilter();
        filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
        context.registerReceiver(receiver, filter);
        return true;
    }


}
2021-09-20T22:46:49   回复
IT小君

白名单可以通过编程方式完成。要在列入白名单的应用程序中添加设备,请从应用程序运行以下命令:

adb shell dumpsys deviceidle whitelist +<package_name>

要从列入白名单的应用程序中删除设备,请从应用程序运行以下命令:

adb shell dumpsys deviceidle whitelist -<package_name>
2021-09-20T22:46:50   回复
IT小君

据我所知,您不能将自己从 Doze 中列入白名单。忽略电池优化不会禁用打瞌睡。请参阅此处:https : //code.google.com/p/android-developer-preview/issues/detail? id = 2225 更新:在 M 的发布版本中,您可以请求忽略电池优化,这至少会给您正常在打盹模式下访问互联网。

2021-09-20T22:46:51   回复
IT小君

更新

当设备再次静止时,屏幕关闭并使用电池一段时间,Doze 会对PowerManager.WakeLock、AlarmManager 警报和 GPS/Wi-Fi 扫描应用完整的 CPU 和网络限制

有关更多详细信息,访问白名单用例

下表突出显示了请求或列入电池优化例外白名单的可接受用例。一般来说,除非 Doze 或 App Standby 破坏了应用程序的核心功能,或者您的应用程序由于技术原因无法使用 GCM 高优先级消息,否则您的应用程序不应在白名单中。

android n 开发人员

打瞌睡特别有可能影响 AlarmManager警报计时器管理的活动,因为当系统处于打盹状态时Android 5.1(API 级别 22)或更低版本中的警报不会触发

Android 6.0(API 级别 23)引入了两个新的 AlarmManager 方法:setAndAllowWhileIdle()setExactAndAllowWhileIdle(). 使用这些方法,您可以设置即使设备处于打盹状态也会触发的警报。

注意每个应用程序每 15 分钟发出一次警报,setAndAllowWhileIdle()setExactAndAllowWhileIdle()不能超过一次。

使用 Doze 和 App Standby 进行测试

2021-09-20T22:46:52   回复