Schedule a GPS location check daily at a predefined time in Android - android

I'm from an iOS background with intermediate Android knowledge. Anyways for this task, I need to know what exactly I need to work with. My app needs to check if the user is at or close to the predefined location at a predefined time. Getting user location is not an issue.
My guess is working with a combination of AlarmManager, BroadcastReceiver and Service ? I haven't worked with either of these three.
Any help is appreciated. :)

These are the ingredients you need for you recipe:
An Intent that targets your BroadcastReceiver:
Intent intent = new Intent(context, YourBroadCastReceiver.class);
A PendingIntent that gets triggered by the AlarmManager and fires your already defined Intent:
PendingIntent pIntent = PendingIntent.getBroadcast(context, requestCode, intent, flags);
The AlarmManager that periodically activates your PendingIntent:
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtMillis, intervalMillis, pIntent);
The BroadCastReceiver that handles the event:
#Override
protected void handleReceive(Context context, Intent intent) {
// handle GPS
}

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

Stopping a repeating alarm from a BroadcastReceiver - is it possible?

I have an AlarmManager that sets a repeating alarm for the purpose of periodically querying a server.
private AlarmManager alarmManager;
private PendingIntent pendingIntent;
alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Intent photosIntent = new Intent(this,AlarmReceiver.class);
//startService(photosIntent);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),0,photosIntent,0);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime(),
10000, pendingIntent);
And I start an IntentService within the AlarmReceiver's onReceive() method. AlarmReceiver is a BroadcastReceiver. Here is the onReceive() method:
#Override
public void onReceive(Context context, Intent intent) {
Intent photosIntent = new Intent(context,JSONPhotosParser.class);
context.startService(photosIntent);
}
Now, this is something crazy I want to do, as it is not very practical. Is there any way I can stop my AlarmManager from within the BroadcastReceiver. I can also think of a practical scenario where such an action would be required. Say I am querying the status of a network connection using ConnectivityManager and if a connection exists I would start an IntentService that queries a server (which is my current scenario). If network status returns false, I would like to stop the repeating alarm set by the AlarmManager.
Is this possible within the BroadcastReceiver ? I understand that an AlarmManager can be removed using cancel(PendingIntent operation). But how do I create PendingIntent inside the BroadcastReceiver ?
Any help on this would be most appreciated. From an Android noob.
refer this link :
AlarmManager.cancel (PendingIntent operation)
http://developer.android.com/reference/android/app/AlarmManager.html#cancel%28android.app.PendingIntent%29

AlarmManager only lets one Service through when used with setRepeating in Android

I've been struggling with this for a couple of days. What I want to do is run a service periodically, about 2-3 minutes apart. I have an Activity that is responsible for the interface and setting up the first alarm.
The alarm is configured by a BroadcastReceiver which looks like this:
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String message = "Alarm worked";
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
setAlarm(context);
}
public void setAlarm(Context context){
AlarmManager am = (AlarmManager) context.
getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Receiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent dailyUpdater = new Intent(context, DiscoveryService.class);
context.startService(dailyUpdater);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (1000 * 30) , pi);
}
}
I've tried using setRepeating for AlarmManager, but it still has the same effect. What happens is that the AlarmManager works how it should, it fires an Intent which the receiver gets and executes onReceive periodically, as it should. However, it executes the service only the first time. After the first time, the alarms still go off, but the service is not executed.
I read some threads from people with similar problems, and one of them mentioned that PendingIntent lasts for only one send. Thus, I opted out to setting the alarm every time so I can set pendingIntent flag for updating every time.
I tried making my service an intentService, which is fine, but then my bluetooth scanner inside the service does not work because intentService thread terminates without waiting for my bluetooth discovery to finish.
Anyone have any idea what can help me?
Here is part of my service:
public class DiscoveryService extends Service {
public void onCreate() {
super.onCreate();
Toast.makeText(this, "MyAlarmService.onCreate()",
Toast.LENGTH_LONG).show();
findEverything();
}
}
EDIT: This is the code that I currently have.
public void onReceive(Context context, Intent intent) {
String message = "Alarm worked";
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
Intent dailyUpdater = new Intent(context, DiscoveryService.class);
context.startService(dailyUpdater);
}
public void setAlarm(Context context){
// get a Calendar object with current time
AlarmManager am=(AlarmManager)context.
getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Receiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
(1000 * 30) , pi);
}
What happens is that the AlarmManager works how it should, it fires an Intent which the reciever gets and executes onReceive periodically, as it should. However, it executes the service only the first time. After the first time, the alarms still go off, but the service is not executed.
You are calling startService() once when you are scheduling the alarm. You are not calling startService() at all from your BroadcastReceiver. Yet you are scheduling the alarm via the BroadcastReceiver. Hence, when the alarm goes off, the service will not be sent a command, because you are not sending it a command.
I read some threads from people with similar problems, and one of them mentioned that PendingIntent lasts for only one send.
That is only if you use FLAG_ONE_SHOT.
Anyone have any idea what can help me?
Call startService() from your onReceive() method, instead of from your setAlarm() method. Also, add in all the WakeLock management logic, since you are using a _WAKEUP alarm and you are not able to use my WakefulIntentService.

How to properly cancel pending alarms

I can't seem to find an answer to this, but what is the criteria for passing in a matching PendingIntent to be removed from an alarm? It it based on the just the name like com.blah.package.myclass or do the Extras matter?
For example, I'm doing something like this and all alarms fire the same intent:
public void setAlarm(Context context, long nextAlarmMillis) {
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra("alarm", this);
PendingIntent sender = PendingIntent.getBroadcast(context, 1234 /* unused */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
am.cancel(sender);
am.set(AlarmManager.RTC_WAKEUP, nextAlarmMillis, sender);
}
What happens is that the Alarm class can be altered, etc and passed in as an Extra. I am canceling the previous alarm, but I'm not sure if it's doing anything or if any left over alarms will remain.
Anyone know for sure?
Following is mentioned in AlarmManager documentation
Any alarm, of any type, whose Intent matches this one (as defined by filterEquals(Intent)), will be canceled.
Which, the filterEquals() is defined as:
Determine if two intents are the same for the purposes of intent resolution (filtering). That is, if their action, data, type, class, and categories are the same. This does not compare any extra data included in the intents.
I think the easiest to do is you keep the reference of PendingIntent passed to AlarmManager, and pass it to cancel. Or have a factory method to construct such pi.

Alarmmanager with pending Intent

The code snippet below....
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
///////////Do something////////////////////////
showtext.startScan();
//SEt Alarm
Intent intent = new Intent(this, TextReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+9000, pi);}
And my Receiver :
TextReceiver extends BroadcastReceiver{
public void onReceive(Context context, Intent intent) {
///Show text/////
}
}
The thing is that when I run the program after 9sn, I am getting an error that "The app stopped unexpectedly". Why I get this error?
My goal is to show the text every 9sn. What is the correct usage of AlarmManager in the main activity
OR Should I set alarm in the BroadcastReceiver ?
Which one does makes sense: am.setRepeating or am.set in terms of my goal?
**Edit: How can I change my alarm code to run in the Broadcast Receiver ? **
//try this
AlarmManager am=(AlarmManager)getApplicationContext getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),(9 * 1000), pendingIntent);
Never, ever use FLAG_CANCEL_CURRENT with PendingIntents that are set as alarms.
What happens is that you wind up canceling the validity of the PendingIntent currently held by the alarm manager, and this means that the alarm manager can no longer tell that any newly-set alarm matches that old PendingIntent. You wind up with the old (invalid) alarm still registered along with your new one. If you keep doing this you can wind up with hundreds (or more!) stale alarms registered in the system, none of which will actually do anything but which are taking up memory and CPU.

Categories

Resources