add Whitelist in Doze mode

최근에 알람 앱을 개발할 일이 있었는데, Doze 모드로 들어가면 알람이 잘 안울리는 일이 있었다. 이 때 사용자에게 ‘배터리 최적화 예외’로 추가해달라고 요청을 해야되는데, 이 글에서는 간단하게 해당 방법을 알아보려 한다.

권한 추가

필요한 권한은 <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />로 위험하지 않은 권한이니 AndroidManifest.xml에만 적어주면 된다.

코드 구현

Doze mode는 6.0 이상에서 구현되었으므로 그 이하에서는 체크할 필요가 없고, 그 전에 이미 배터리 예외 모드에 추가되어 있으면 요청할 필요가 없어진다.

이를 반영한 코드는 다음과 같다.

@SuppressLint({"BatteryLife", "InlinedApi"})
    private void checkBatteryOptimization(Consumer<Boolean> callback) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { // 버전 체크
            Log.d(TAG, "checkBatteryOptimization: The version is too low to be checked.");
            callback.accept(true);
            return;
        }

        String packageName = getApplication().getPackageName();

        // since REQUEST_IGNORE_BATTERY_OPTIMIZATIONS is **not** dangerous permission,
        // but we need to check that app has `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` permission.
        if (PackageManager.PERMISSION_GRANTED != getApplication().getPackageManager()
                .checkPermission(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
                        getApplication().getPackageName())) { // 권한 체크
            Log.d(TAG, "checkBatteryOptimization: application hasn't REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission");
            return;
        }

        PowerManager powerManager = (PowerManager) getApplication().getSystemService(Context.POWER_SERVICE);
        boolean ignoringBatteryOptimizations = powerManager.isIgnoringBatteryOptimizations(packageName);
        if (ignoringBatteryOptimizations) { // 예외사항에 이미 추가되었는지 확인
            Log.d(TAG, "checkBatteryOptimization: Already ignored Battery Optimizations.");
            callback.accept(true);
            return;
        }

        Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
        intent.setData(Uri.parse(String.format("package:%s", packageName)));
        startActivity(intent);
    }

마지막으로 사용하는 곳에서 체크하면 된다.

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
    checkBatteryOptimization(result -> DailyAlarmAnalyze.schedule());
}

결과