I am working with AlarmManager, It is not working on android os 6.0.
This is my code:
private void startAlarmManager(String id) {
userID = GlobalValue.getUserName(GuideNavigationActivity.this);
Context context = getBaseContext();
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
gpsTrackerIntent = new Intent(context, GpsTrackerAlarmReceiver.class);
gpsTrackerIntent.putExtra("id", id);
gpsTrackerIntent.putExtra("userID", userID);
gpsTrackerIntent.putExtra("idCourse", idCourse.toString());
gpsTrackerIntent.putExtra("typeCourse", typeCourse);
pendingIntent = PendingIntent.getBroadcast(context, 0, gpsTrackerIntent, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,System.currentTimeMillis()+ Constant.GPS_INTERVAL, pendingIntent);
}
else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,System.currentTimeMillis()+ Constant.GPS_INTERVAL, pendingIntent);
} else {
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,System.currentTimeMillis()+ Constant.GPS_INTERVAL, pendingIntent);
}
}
Please support me. Thank so much.
AlarmManager will not allow you to repeat that frequently, even through manual steps (e.g., setExactAndAllowWhileIdle()), on Android 5.1+.
Moreover, using AlarmManager for that frequent of an event is very inefficient, on all versions of Android. This is one of the reasons why Android no longer supports it, as too many developers were doing inappropriate things with AlarmManager and wasting users' batteries as a result.
If you need to get control every second, use some in-process solution, such as ScheduledExecutorService. Or, since your names suggest that you are tracking the location, use the appropriate APIs to let you know when the location changes, rather than trying to get control every second.
Related
I have implemented AlaramManager with background service, It works fine on devices below Oreo. But doesn't work on android Oreo and above as Google stopped background services from working on Oreo and Above.
Is there any source code or any kind resource which will help me to set alarms on android Oreo or above devices?
After searching for a while I found out about JobsIntentService, but couldn't found enough information about it. And I don't know if it is the way to go. Basically, I want to show notifications on particular dates and times.
Thanks in Advance.
Please try bellow method it will work for you.
/**
* Method for start Alarm on defined minute
* #param minutes Minute when you want to start after current time
* #param context
*/
public static void startAlarm(Context context, int minutes) {
Logger.print("AlarmReceiver startAlarm called");
Intent alarmIntent = new Intent(context, WakefulBroadcastReceiverService.class);
alarmIntent.setAction("testAPP");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 123451, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
long alarmPeriodicTime = System.currentTimeMillis() + Utils.getTimeInMilliSec(Constant.TimeType.MINUTE, minutes);
if (Build.VERSION.SDK_INT >= 23) {
manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmPeriodicTime, pendingIntent);
} else if (Build.VERSION.SDK_INT >= 19) {
manager.setExact(AlarmManager.RTC_WAKEUP, alarmPeriodicTime, pendingIntent);
} else {
manager.set(AlarmManager.RTC_WAKEUP, alarmPeriodicTime, pendingIntent);
}
}
I had been tasked with developing an alarm app. Something simple which lets users set an alarm at a specific time and select a music file that should play when the alarm goes off. The app works great on phone like Samsung, Motorola, and Nexus but on Xiomi, Oppo, Vivo phones the alarm does not go off at the correct times and sometimes it does not fire at all. I have used Android's AlarmManager APIs. I am wondering if there is something else I need to do to get the alarm to work as expected on devices like xiomi, oppo, and vivo. Most of the solutions on StackOverflow have not worked out for me. If there are devs here in this subreddit who have worked with AlarmManager APIs before or worked on Apps with Alarm features, id really appreciates some more insight into AlarmManager APIs and why they don't work as expected across all phones and if there are any alternatives I should be using.
Bellow is the method which will help you, Which I tested with the different-different device it's working.
/**
* Method for start Alarm on Defined time
*
* #param context
*/
public static void startAlarm(Context context,int minutes) {
Logger.print("AlarmReceiver startAlarm called");
Intent alarmIntent = new Intent(context, WakefulBrodcastReceiverService.class);
alarmIntent.setAction("testAPP");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 123451, alarmIntent, 0);
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
long alarmPeriodicTime = System.currentTimeMillis() + Utils.getTimeInMilliSec(Constant.TimeType.MINUTE, minutes);
if (Build.VERSION.SDK_INT >= 23) {
manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmPeriodicTime, pendingIntent);
} else if (Build.VERSION.SDK_INT >= 19) {
manager.setExact(AlarmManager.RTC_WAKEUP, alarmPeriodicTime, pendingIntent);
} else {
manager.set(AlarmManager.RTC_WAKEUP, alarmPeriodicTime, pendingIntent);
}
}
My alarm clock app uses AlarmManager to set alarms and I have a problem with PendingIntents being cancelled when I close the app from recent app list (it happens occasionally on a KitKat device and almost constantly on Marshmallow), even if the alarm was set a couple minutes ago (so device is not asleep).
Here's how I set an alarm:
Calendar alarmCalendar = getCalendarForDay(day);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
(id * 10000 + day.position), getIntent(context, day.position), FLAG_UPDATE_CURRENT);
long intervalMsec = alarmCalendar.getTimeInMillis();
if (android.os.Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, intervalMsec, pendingIntent);
} else alarmManager.set(AlarmManager.RTC_WAKEUP, intervalMsec, pendingIntent);
getIntent():
private Intent getIntent(Context context, int dayPosition) {
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra(MainActivity.PACKAGE_NAME + ".alarmId", id);
intent.putExtra(MainActivity.PACKAGE_NAME + ".dayPosition", dayPosition);
return intent;
}
I've spent quite a while browsing this site and found some explanations here and here (basically says that it's normal and some manufacturers just do that), but none of them have actually helped me to deal with the problem. Still, I'm pretty sure that canbe solved, since there are some apps that work on all devices (such as Timely and other popular alarm clocks).
So does anyone have any thoughts on how those alarms actually deal with AlarmManager? Why their intents are never get cancelled?
I need to plan sheduled task every 10 minutes.
As in Lollipop and higher version setRepeating() is inexact, I use setExact() and (on alarm firing) I set new exact alarm in 10 minutes.
private void setAlarm(long triggerTime, PendingIntent pendingIntent) {
int ALARM_TYPE = AlarmManager.ELAPSED_REALTIME_WAKEUP;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(ALARM_TYPE, triggerTime, pendingIntent);
} else {
alarmManager.set(ALARM_TYPE, triggerTime, pendingIntent);
}
}
triggerTime is calculated SystemClock.elapsedRealtime() + 600_000;
When alarm fires, firstly I plan new one, only after that I run my sheduled task.
setAlarm();
mySheduledTask;
I do have WAKE_LOCK permission in my manifest.
When I test this on Android 4 - it works perfect (deviation might be 12-15 milliseconds).
But when I run app on Xiaomi Redmi Note 3 Pro (5.1.1) - deviation can be up to 15 seconds!
For example, I see in my log file: first run was at 1467119934477 (of RTC time), second - at 1467120541683. Difference is 607_206 milliseconds, not 600_000, as it was planned!
What am I missing? What is a way to simulate behaviour of system alarm (it's the most close usecase that can describe my tack)?
PS. I use IntentService for PendingIntent = PendingIntent.getService(context, 0, myIntent, 0);
The OS chooses how the alarms will work, with consideration of the time you've specified. Because of that, when the phone gets into a 'semi-sleep' mode, it won't necessary use the resource at the time you wish it to. Basically, it waits for 'windows' that the OS opens for it, and only then the alarm you want to run will run, that's why you're experiencing time gaps.
This was introduced on Marshmallow OS and will continue on Nougat OS as well, as part of Google trying to improve the device's battery.
Here's the thing, you have 2 options:
Accept the time delays (but maybe consider using JobScheduler which is more recommended and will save you battery).
Use setExactAndAllowWhileIdle which might cause you battery issues (use this carefully, too many alarms will be bad for your battery).
This method isn't repeating, so you have to declare the next job to be run at the service which the pendingIntent opens.
If you choose option 2, here's the start:
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
int ALARM_TYPE = AlarmManager.RTC_WAKEUP;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
am.setExactAndAllowWhileIdle(ALARM_TYPE, calendar.getTimeInMillis(), pendingIntent);
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
am.setExact(ALARM_TYPE, calendar.getTimeInMillis(), pendingIntent);
else
am.set(ALARM_TYPE, calendar.getTimeInMillis(), pendingIntent);
You can call the method from support.v4:
AlarmManagerCompat.setExact(...);
The internal implementation contains checks by sdk version.
Probably a possible workaround could be something like this:
you schedule the Alarm about 1 minute before the expected time, than you use a Handler.postDelayed to cover the remaining time.
Here you can find an example of this kind of implementation.
The activity just set-up the first alarm:
public class MainActivity extends AppCompatActivity {
private static int WAIT_TIME = 60*1000; //1 minute
public static int DELAY_TIME = 10*60*1000; // delay between iterations: 10min
public static String UPDATE_TIME_KEY = "update_time_key";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setAlarm(this,(new Date().getTime())+DELAY_TIME);
}
public static void setAlarm(Context context, long delay) {
long fireDelay = delay-WAIT_TIME;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
sharedPreferences.edit().putLong(UPDATE_TIME_KEY,delay).apply();
Intent startIntent = new Intent(context, UpdateReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, startIntent,PendingIntent.FLAG_UPDATE_CURRENT );
AlarmManager alarmManager = (AlarmManager) context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
int ALARM_TYPE = AlarmManager.RTC;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(ALARM_TYPE, fireDelay, pendingIntent);
} else {
alarmManager.set(ALARM_TYPE, fireDelay, pendingIntent);
}
}
}
than the receiver continues the loop:
public class UpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
Log.e("RECEIVED","RECEIVED");
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
long fireTime = sharedPreferences.getLong(MainActivity.UPDATE_TIME_KEY, (new Date()).getTime());
long fireDelay =(fireTime-(new Date().getTime())>0)?fireTime-(new Date().getTime()):0;
(new Handler()).postDelayed(new Runnable() {
#Override
public void run() {
Log.e("RECEIVED","PERFORMED");
MainActivity.setAlarm(context,(new Date()).getTime()+MainActivity.DELAY_TIME);
}
},fireDelay);
}
}
I hope it helped.
To answer the question on the system alarm...
Android's stock Alarm Clock/Desk Clock app uses a combination of setAlarmClock and setExactAndAllowWhileIdle.
The following code is used to update notifications:
final PendingIntent operation = PendingIntent.getBroadcast(context, 0,
AlarmStateManager.createIndicatorIntent(context), flags);
final AlarmClockInfo info = new AlarmClockInfo(alarmTime, viewIntent);
alarmManager.setAlarmClock(info, operation);
While at the same time the following code is used to schedule the actual alarm:
if (Utils.isMOrLater()) {
// Ensure the alarm fires even if the device is dozing.
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeInMillis, pendingIntent)
}
The Pending intent set in setExactAndAllowWhileIdle triggers the alarm while setAlarmClock's intent is then simply ignored.
Android Googlesource
From android documentation of AlarmManager
Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
Also while using setExact() :
The alarm will be delivered as nearly as possible to the requested trigger time.
So its still not guaranteed that setExact will be Exact.
You can try use AlarmManager.setAlarmClock maybe it can help you.
Another thing you need to check which type of BroadcastReceiver you are using, it will be better to use WakefulBroadcastReceiver
Btw you need to change logic for work with Alarm Manager for support Android M, you can you something like this:
if(Build.VERSION.SDK_INT < 23){
if(Build.VERSION.SDK_INT >= 19) {
setExact(...);
} else {
set(...);
}
} else {
setExactAndAllowWhileIdle(...);
}
I have a big problem with Android KitKat and Alarm Manager.
All my apps work with a service that always run in background without Android kill it.
Before Android 4.4 KitKat the solution I found was to start the service through a BroadcastReceiver triggered by an AlarmManager.
...
Intent intent = new Intent(c, MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(c, 0, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager am = (AlarmManager) c.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT<Build.VERSION_CODES.KITKAT) {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), pendingIntent);
} else {
setAlarmFromKitkat(am, System.currentTimeMillis(), pendingIntent);
}
...
#TargetApi(19)
private static void setAlarmFromKitkat(AlarmManager am, long ms, PendingIntent pi){
am.setExact(AlarmManager.RTC_WAKEUP, ms, pi);
}
...
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, MyService.class);
context.startService(service);
}
}
On Android 4.4 KitKat by this solution I can start service but after some time Android kill it!
Is there a way to have a Service that works in background without Android 4.4 KitKat kill it?
Many Thanks
For Android Kitkat version
If your app uses AlarmManager...
When you set your app's targetSdkVersion to "19" or higher, alarms that you create using either set() or setRepeating() will be inexact.
To improve power efficiency, Android now batches together alarms from all apps that occur at reasonably similar times so the system wakes the device once instead of several times to handle each alarm.
If your alarm is not associated with an exact clock time, but it's still important that your alarm be invoked during a specific time range (such as between 2pm and 4pm), then you can use the new setWindow() method, which accepts an "earliest" time for the alarm and a "window" of time following the earliest time within which the system should invoke the alarm.
If your alarm must be pinned to an exact clock time (such as for a calendar event reminder), then you can use the new setExact() method.
This inexact batching behavior applies only to updated apps. If you've set the targetSdkVersion to "18" or lower, your alarms will continue behave as they have on previous versions when running on Android 4.4.
Original Source:
http://developer.android.com/about/versions/android-4.4.html
in kitkat,use the code snippet below to restart te service automatically:
#Override
public void onTaskRemoved(Intent rootIntent) {
// TODO Auto-generated method stub
Intent restartService = new Intent(getApplicationContext(),
this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartServicePI = PendingIntent.getService(
getApplicationContext(), 1, restartService,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() +1000, restartServicePI);
}