setExactAndAllowWhileIdle() for alarmmanager is not working properly

you can whitelist your app from doze mode by ignoring battery optimizations..

Add permission

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

request whitelist your app

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

Note: Neither setAndAllowWhileIdle() nor setExactAndAllowWhileIdle() can fire alarms more than once per 15 minutes per app.


I've found the solution for my problem so, i am posting my own answer here which worked for me.

Using setAlarmClock() method has solved my problem. If you set alarm using setAlarmClock() method then this will not allow the system to go into doze mode before 1 hour of your alarm's time. I had tested this by manually forcing my device to go into doze mode after setting my alarm. Let me explain full scenario.

  1. First of all i set alarm after 5 minutes from current time and then tried to putting my device into doze mode manually by using following command.

adb shell dumpsys deviceidle force-idle

It Shows

unable to enter into doze mode

  1. After that i set alarm after 1 hour and 1 minute from current time and then i have tried to put my device into doze mode and it enters into doze mode successfully. Then i have done nothing on my device and it fires alarm exactly on time even it was in a doze mode.

Hence, i conclude that setAlarmClock() method prevents your device from entering to doze mode if there is a small amount of timestamp between current time and your alarm time. Otherwise if your device is already in doze mode then it will gets exit from doze mode before some time of your alarm so, your alarm works fine.

Updated code:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
    alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(d.getTime(),pendingIntent),pendingIntent);
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
    alarmManager.setExact(AlarmManager.RTC, d.getTime(), pendingIntent);
else
    alarmManager.set(AlarmManager.RTC, d.getTime(), pendingIntent);