7

Application is running SDK 23 and above. I am running some tasks using Service after completing the task and scheduling the next task using AlaramManager (setExactAndAllowWhileIdle). This is working fine. If the phone is idle continuously for 2 or 3 days then its going to Doze mode. After Doze mode ,application loosing the network and wakelock also not working.

Is there way even if phone is Doze can we run the application with any network interposition issues.I tried to keep the application witelist but i needs device to be rooted.

adb shell dumpsys deviceidle whitelist +<Package Name>

Can anyone suggest me which best way to run application without interruption?

Srikanth
  • 584
  • 1
  • 6
  • 21

4 Answers4

8

Actually there is no way of doing this without running a foreground service. Having listed in white list may not be appropriate for your application and even though it is, you ask user to give you permission which can be seen as something dangerous from the end user's point of view.

However, I have a trick about this. Listen android's broadcasts and when you catch that device will move into doze mode, start a foreground service. In most of the cases user won't be able to see your foreground notification image and won't know that you are running a service. Because device is in the doze mode meaning it is stable in somewhere user not watching. So you can do whatever is needed.

You also listen broadcasts sent when doze mode is finished. When that happens, stop your foreground service and work in a normal logic of yours with alarm managers.

PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if(intent.getAction().equals("android.os.action.DEVICE_IDLE_MODE_CHANGED")){
        if (pm.isDeviceIdleMode()) {
            startForegroundService();
            //stopAlarmManagerLogic();
        } else {
            stopForegroundService();
            //startAlarmManagerLogic();
            return;
        }
        return;
    }
}
Mertcan Çüçen
  • 466
  • 3
  • 13
  • this answer inspired me to find a good solution that will run the service forever even when the phone in doze mode. – Desolator Oct 28 '19 at 03:12
3

You can request android to whitelist your app for doze mode by sending a high pirority GCM message. But remember this might make your app not approved by Google Play:

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);

https://developer.android.com/training/monitoring-device-state/doze-standby.html#whitelisting-cases

mehulmpt
  • 15,861
  • 12
  • 48
  • 88
  • That's fine even if don't approved by Google Play. is FCM high priority message how long device can wakeup from Doze? i have implemented this. Is the above code from app witelist. How can i confirm that? – Srikanth Apr 24 '17 at 19:59
  • 1
    @srikanth the code asks for permission for `ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS` at runtime. If you read here: https://developer.android.com/training/monitoring-device-state/doze-standby.html#support_for_other_use_cases you'll see their docs say that it gives you access to partial wakelocks again which your app was missing – mehulmpt Apr 24 '17 at 20:05
3

Edit-WakefulBroadcastReceiver is now deprecated

Firstly, instead of directly calling a service in the AlarmManager call a broadcast receiver which then calls the service.

The broadcast receiver should extend a WakefulBroadcastReceiver instead of a regular BroadcastReceiver.

And then, let the broadcast receiver schedule a new Alarm, start the service using startWakefulService() instead of startService()

public class MyAwesomeReceiver extends WakefulBroadcastReceiver {
int interval=2*60*60*1000;
    @Override
    public void onReceive(Context context, Intent intent) {

        Intent serviceIntent = new Intent(context, MyAwesomeService.class);
        Intent receiverIntent = new Intent(context, MyAwesomeReceiver.class);

        PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 11, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+interval,alarmIntent);
        startWakefulService(context, serviceIntent);
        }
}

The WakefulBroadcastReceiver and startWakefulService() will let your app a 10 seconds window to let do what it needs to do.

Also,

You can always ask the user to let your app ignore battery optimization functionality using-

PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
Intent intent=new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
if (powerManager.isIgnoringBatteryOptimizations(getPackageName())) {
     intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
}
else {
     intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
     intent.setData(Uri.parse("package:" + getPackageName()));
     startActivity(intent);
}

and in the manifest

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"></uses-permission>
Darshan Miskin
  • 844
  • 14
  • 25
0

After Android N, no app can run in background forever. However you can use Firebase Job Dispatcher which can help you to run your app even if it is in doze mode. With the help of Firebase Job Dispatcher you can tell the system that your app should run at a particular time if provided conditions are matched.

Mehul Kanzariya
  • 888
  • 3
  • 27
  • 58