Set alarm in service and receive callback in the same service - android

My ReminderService uses the AlarmManager to inform the user about an upcoming event at a specific time. Is it possible that the AlarmManager informs the same service (ReminderService) or do I need to start another service to catch the pending intent? Until now this mechanism looks like this
public class ReminderService extends Service {
// ...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// ..
/* When the alarm goes off the NotifyService will be started. Is it possible to inform **this**
service (ReminderService) and to handle the alarm? */
Intent alarmIntent = new Intent(this, NotifyService.class);
alarmIntent.putExtra(TodoTask.PARCELABLE_KEY, task);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, alarmIntent, 0);
Calendar calendar = Calendar.getInstance();
Date date = new Date(reminderTimeStamp*1000);
calendar.setTime(date);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
}

yes u can. You just need to change this line:
Intent alarmIntent = new Intent(this, NotifyService.class);
to this:
Intent alarmIntent = new Intent(this, ReminderService.class);
that way the ReminderService will receive the intent with TodoTask.PARCELABLE_KEY inside this same method public int onStartCommand(Intent intent, int flags, int startId)
Remember that there no guarantee that this will be the same instance of the service. If the service you're running get killed by the system a new instance of it will be started to handle the intent.
Also remember all the sleep and doze mode stuff mentioned by Larry_Schiefer on his answer.

You can use the same Service (or other component) to receive an alarm. However, not that your alarm will not be guaranteed to be delivered on schedule when in low power. Use a WakefulReceiver or your own combination of BroadcastReceiver and a wakelock to get your Service going. See this article for more details on power state and alarms.
Also, note that starting with Android Marshmallow your wakelocks will be ignored if the device is in Doze mode. There are other things you'll have to do to wake the device at a certain time when in Doze.

Related

How to keep a service alive using AlarmManager.setInexactRepeating()?

I have some existing code that spawns a service intent which does a bunch of stuff in the background. This code does work...
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(serviceIntent);
My question is: how to change this to use the AlarmManager.setInexactRepeating(...) methods?
I have changed the above code to this:
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.putExtra("STARTED_BY", starter);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//Set up recurring alarm that restarts our service if
// it crashes or if it gets killed by the Android OS
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getService(context, 0, serviceIntent, 0);
//am.cancel(pi);
am.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP //wake up the phone if it's asleep
, cal.getTimeInMillis()
, 10000
, pi);
And I have added these permissions to AndroidManifest.xml...
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="com.android.alarm.permission.WAKE_LOCK"/>
My understanding is that this is supposed to start the service immediately and then try to restart it again every 10 seconds. But this code isn't working properly.
Using this new code, the service never starts at all and I cannot see why not. To complicate matters the debugger never seems to attach to the app in time to see what's going on.
Can anyone see what I'm doing wrong?
Put AlarmManager code under onDestroy() function of service to schedule start of service as below:
#Override
public void onDestroy() {
/**
* Flag to restart service if killed.
* This flag specify the time which is ued by
* alarm manager to fire action.
*/
final int TIME_TO_INVOKE = 5 * 1000; // try to re-start service in 5 seconds.
// get alarm manager
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AutoStartServiceReceiver.class);
PendingIntent pendingIntent = PendingIntent
.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// set repeating alarm.
alarms.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() +
TIME_TO_INVOKE, TIME_TO_INVOKE, pendingIntent);
}
And handle starting of your service in AutoStartServiceReceiver as below:
public class AutoStartServiceReceiver extends BroadcastReceiver {
private static final String TAG = AutoStartServiceReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
// check broadcast action whether action was
// boot completed or it was alarm action.
if (intent.getAction().equals(AppConstants.ACTION_ALARM_INTENT)) {
context.startActivity(new Intent(context, YourActivity.class));
// handle service restart event
LockerServiceHelper.handleServiceRestart(context);
}
}
}
Kindly note that, your service will not restart if you stop it manually from settings-apps-running apps-your app.
Your service is not starting because of AlarmManager.ELAPSED_REALTIME_WAKEUP, while it should be using AlarmManager.RTC_WAKEUP
If you want to run every 10s keep in mind that above API 21 alarm intervals below 60s are rounded up to 60s.
Also, consider using WakefulIntentService
https://github.com/commonsguy/cwac-wakeful

Function of Service in Context of Alarm App (Android)

I am trying to develop an alarm system in android that would function after the application closes, making multiple simultaneous alarms possible (which should be repeatable and cancelable, but I have read documentation for such functions).
Currently, I only have the UI (which fires off intents to receiver at scheduled times through AlarmManager) and the Receiver class (which extends BroadCastReceiver). Although the alarm somehow functions, there have been issues like the alarm not sounding at appropriate times until I open app again and not providing the correct alarm.
I have read that a service is commonly used in such apps to provide functionality of the application when the activity is closed. Thus, I am interested in what a service would provide in the context of the application, and whether my problems are solvable through service.
I have searched answers and read that a service is useful for running background operations (i.e. mp3 or alarm) For example, google states that "Another application component can start a service and it will continue to run in the background even if the user switches to another application. ". The following answer states that to use "alarm simultaneously you must use Service class for that".
Therefore, I think that a service may be useful for providing the functionality for the alarm. However, some people seem to represent a service as a either or with AlarmManager, which I am currently using. Most others seem to use AlarmManger to start service or perform an action of that nature. I would be very grateful if someone could shed light on what a service provides (I've already read google's explanation but it did not clear up whether I need it or not).
Sending intent from UI
if (row.get(7) == 1) {
Intent alarmIntent = new Intent(MainActivity.this, AlarmReceiver.class);
alarmIntent.putExtra("id", (long) row.get(0));
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
long longValue = (long) row.get(0);
int intValue = (int) longValue;
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, intValue, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (row.get(8) == 1) {
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, (long) row.get(6), (long) row.get(9), pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, (long) row.get(6), pendingIntent);
}
}
AlarmReceiver class
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
long id = intent.getLongExtra("id", 0);
Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(R.drawable.ic_action_search)
PendingIntent pi = PendingIntent.getActivity(context, (int)id, new Intent(), 0);
NotificationManager nm = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify((int)id, builder.build());
}
}
Try to use service like this :
public class UpdateService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return START_STICKY;
}
}
When onStartCommand returns START_STICKY, system restarts service if it's killed.
Use this link

Android is killing my service?

with a BroadCastReceiver, I execute a service at the smartphone boot:
public class BootReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent startServiceIntent = new Intent(context, MyService.class);
context.startService(startServiceIntent);
}
}
MyService:
private Runnable myRunnable = new Runnable() {
public void run() {
parsing.cancel(true);
parsing = new Parsing();
parsing.execute();
handler.postDelayed(this, timeoutUpdate);
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler.removeCallbacks(myRunnable);
handler.postDelayed(myRunnable, 1000);
return Service.START_STICKY;
}
The service is really executed at the boot, but if I set a timeout of 1 hour between executions, service is not executed (maybe the system is killing it). Otherwise, if I set 60 sec between repetition, all works.
How can I do it? Thanks.
You may run the service in the foreground using startForeground().
A foreground service is a service that's considered to be something
the user is actively aware of and thus not a candidate for the system
to kill when low on memory.
But bear in mind that a foreground service must provide a notification for the status bar (read here), and that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
Note: This still does not absolutely guarantee that the service won't be killed under extremely low memory conditions. It only makes it less likely to be killed.
OR
If you dont want to run the service in the foreground then you can run service in a periodic intervals using AlarmManager
Intent intent = new Intent(context, MyService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), AlarmManager.INTERVAL_HOUR, pintent);
Update
Cancel the registered event by using
Intent intent = new Intent(context, MyService.class);
PendingIntent pintent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarm = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pintent);
To schedule a job use AlarmManager in BroadcastReciever.
Intent intent = new Intent(context, MyService.class);
PendingIntent pintent = PendingIntent.getService(context, 0, intent, 0);
AlarmManager alarm = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarm. setRepeating(AlarmManager.RTC_WAKEUP, triggerInMillis, intervalMillis, pintent);
System will awake your service and then you will be able to execute task immediately.
set highest priority for your service
<intent-filter
android:priority="integer" >
</intent-filter>
The value must be an integer, such as "100". Higher numbers have a higher priority. The default value is 0. The value must be greater than -1000 and less than 1000.

Android Alarm Manager setting strange schedule

I am having a problem with trying to schedule my service to run every so often. I have gotten my service to start on boot, but for what ever reason when the schedule starts is starts the service way to many times.
public class PPPService extends Service {
public void onStart(Intent intent, int startId) {
//TODO do something useful
Log.v("TEST", "Service started");
// Schedule the alarm!
PendingIntent mAlarmSender = PendingIntent.getService(this, 0, intent, 0);
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, AlarmManager.INTERVAL_FIFTEEN_MINUTES, mAlarmSender);
this.stopSelf();
}
}
Resolved: This was resolved by creating a Scheduler instead of having my service schedule itself.
You are sending in the PendingIntent the context of your service that will be killed very soon along with the intent which started it. I guess this can be quite unpredictable. Try getting the pending intent like this:
mAlarmSender = PendingIntent.getService(getApplicationContext(), 0, new Intent(getApplicationContext(), PPPService.class), 0);

How to prevent AlarmManager from being recreated with Server?

I have this Service that do other stuff in the background and must always be running. On its onCreate i've set an Alarm that sends an email once a day. The server is not running in foreground, so sometimes its get killed by the system, and then created again, and when that happens its creates the alarm again, and sends another email every time it happens. So my question is, is there a way to prevent it from triggering the alarm if its already set for repeating in the system? Or is there another "place" in the Service where i can create the alarm once and prevent it for being recreated with the it?
public class ObserverService extends Service {
private String BABAS = "babas";
#Override
public void onCreate() {
setRecurringAlarm(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void setRecurringAlarm(Context context) {
Log.i(BABAS, "entrou no set alarme");
Calendar updateTime = Calendar.getInstance();
updateTime.setTimeZone(TimeZone.getDefault());//getTimeZone("GMT"));
updateTime.set(Calendar.HOUR_OF_DAY, 00);
updateTime.set(Calendar.MINUTE, 00);
Intent downloader = new Intent("ALARME");//context, AlarmReceiver.class);
PendingIntent recurringDownload = PendingIntent.getBroadcast(context,
0, downloader, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, recurringDownload);
}
}
If that code is everything your Service does you can completely get rid of the Service.
The only thing the service does is schedule a Broadcast once a day on the alarm manager, why not do this schedule directly from the Activity?
edit:
Given your comment, my original answer remains:
The Alarm set on the AlarmManager is permanent until the device is turned off or rebooted.
So you can set the first alarm via Activity and mark it as active on the SharedPreferences. Create a BroadcastReceiver to receive onBoot events, this receiver will check the SharedPreferences for if the alarm is active and in case it is, re-register it on the AlarmManager.
Your service still does the same ContentObserver stuff, but have no association with the recurring AlarmManager event.
I reckon that would be cleanest solution.
Alternatively (but I don't think it's a good/clean solution), you can use the AlarmManager.cancel() to remove the existing PendinIntent, and then re-trigger it
http://developer.android.com/reference/android/app/AlarmManager.html#cancel(android.app.PendingIntent)

Categories

Resources