androidandroid-serviceandroid-dozeandroid-doze-and-standbyxiaomi

Avoid doze mode programmatically


I'm developing an Android app that uses Xiaomi Mi Band 1S to keep measurements of heart rate all the time. I use a service to handle Bluetooth connection and I already achieved to keep this service alive when the app is close, and even to restart the service when the mobile is rebooted.

Now, my problem comes with android doze mode. I'm using the following tricks to keep the service alive:

CODE

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  Intent intent = new Intent();
  String packageName = getPackageName();
  PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
  if (powerManager != null && !powerManager.isIgnoringBatteryOptimizations(packageName)){
    intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
    intent.setData(Uri.parse("package:" + packageName));
    startActivity(intent);
  }
}

PROBLEM

My mobile phone is a Xiaomi. Both, BOOT_COMPLETED and IGNORE_BATTERY_OPTIMIZATIONS, aren't working. They only work if I set the permissions manually. I also added the required permissions to the manifest file.

So is there a way to allow these permissions without the user having to set them manually? Applications like WhatsApp or Skype have these permissions by default. Why I can't do the same?

Also, this is happening on Xiaomi mobile. It will also happen in all other mobile devices?


Solution

  • I've stumbled on the same problem a few months back. The thing is that all the popular apps like WhatsApp and Skype and all have been allowed by Xiaomi by default but not your app. Don't know what kind of deal there are doing in the background, but it seems unfair to developers.

    Now the solution, this piece of code will lead to the permission setting of Xiaomi and other mobile brands, those customize their ROMs and do as they want-

    private void specialPermission() {
        String alertMessage = "Please allow APP_NAME to always run in the background, else our services can't be accessed when you are in distress.";
        final String brand = Build.BRAND;
        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
        builder.setMessage(alertMessage);
        builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Intent intent = new Intent();
                if (brand.equalsIgnoreCase("xiaomi")) {
                    intent.setComponent(new ComponentName("com.miui.securitycenter",
                            "com.miui.permcenter.autostart.AutoStartManagementActivity"));
                    startActivity(intent);
                } else if (brand.equalsIgnoreCase("Letv")) {
                    intent.setComponent(new ComponentName("com.letv.android.letvsafe",
                            "com.letv.android.letvsafe.AutobootManageActivity"));
                    startActivity(intent);
                } else if (brand.equalsIgnoreCase("Honor")) {
                    intent.setComponent(new ComponentName("com.huawei.systemmanager",
                            "com.huawei.systemmanager.optimize.process.ProtectActivity"));
                    startActivity(intent);
                } else if (Build.MANUFACTURER.equalsIgnoreCase("oppo")) {
                    try {
                        intent.setClassName("com.coloros.safecenter",
                                "com.coloros.safecenter.permission.startup.StartupAppListActivity");
                        startActivity(intent);
                    } catch (Exception e) {
                        try {
                            intent.setClassName("com.oppo.safe",
                                    "com.oppo.safe.permission.startup.StartupAppListActivity");
                            startActivity(intent);
                        } catch (Exception ex) {
                            try {
                                intent.setClassName("com.coloros.safecenter",
                                        "com.coloros.safecenter.startupapp.StartupAppListActivity");
                                startActivity(intent);
                            } catch (Exception exx) {
                                exx.printStackTrace();
                            }
                        }
                    }
                } else if (Build.MANUFACTURER.contains("vivo")) {
                    try {
                        intent.setComponent(new ComponentName("com.iqoo.secure",
                                "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity"));
                        startActivity(intent);
                    } catch (Exception e) {
                        try {
                            intent.setComponent(new ComponentName("com.vivo.permissionmanager",
                                    "com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
                            startActivity(intent);
                        } catch (Exception ex) {
                            try {
                                intent.setClassName("com.iqoo.secure",
                                        "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager");
                                startActivity(intent);
                            } catch (Exception exx) {
                                ex.printStackTrace();
                            }
                        }
                    }
                }
            }
        });
        AlertDialog dialog = builder.create();
        dialog.show();
    }
    

    All you have to do is show a dialog that will describe your necessity for the background services and open the permission settings. Even though it's not a complete fix as SWIPE KILL, will stop the service anyway.