Android - Periodically broadcast an event - android

How do I periodically broadcast an event after user has installed my application.
I have implemented a broadcast receiver which will trigger a task onReceive. Now I need to periodically broadcast this event, so that the task will be executed periodically.
I know I need to use AlarmManager.
The code is somewhat like this.
Intent intent = new Intent(this, MyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this.getApplicationContext(), 234324243, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, 0, 5*1000, pendingIntent);
Q1) Where do I place this code if I do not have any Activity? Do I implement this as a service?
Q2) What should be the intent-filter be for my manifest in such a "self created event"?
PS: Actually my current broadcast receiver is waiting for the connectivity change event. The task is to periodically attempt/try to access the internet. But I cannot solely rely on connectivity change to trigger this task. That's why I need a timer which will either fire this event or trigger the method in onReceive().
I know in this case my intent-filter will be "android.net.conn.CONNECTIVITY_CHANGE"

Q1) Where do I place this code if I do not have any Activity?
You need to implement an activity. Nothing of your application will run on Android 3.1+ until the user has launched your activity.
So, you run this code:
The first time the user runs your activity
On a reboot (via a BOOT_COMPLETED BroadcastReceiver)
In the future when the user runs your activity, if you have determined that no broadcasts have gone out in too long, because the user force-stopped your application
Also, get rid of getApplicationContext(), as you should not need it here.
Q2) What should be the intent-filter be for my manifest in such a "self created event"?
You do not need one, as your Intent identifies the component.

Related

PendingIntent with IntentService not working

Following code works perfectly for Activity:
Intent intent = new Intent(context, MyActivity.class);
PendingIntent operation = PendingIntent.getActivity(context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
alarmmanager.setExact(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis(),
operation);
However, when I do the same thing for IntentService, It works only if startTime and time I set alarm are on the same day. e.g. If I set the alarm today for 5 PM, it will be executed but when I set the alarm today for 5 PM tomorrow, it will not be executed. If this was Activity then it works for both cases.
Intent intent = new Intent(context, MyService.class);
PendingIntent operation = PendingIntent.getService(context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
alarmmanager.setExact(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis(),
operation);
How to solve this?
The goal here I am trying to achieve is to execute IntentService every day at the exact time.
The goal here I am trying to achieve is to execute IntentService every day at the exact time.
Google has made this progressively harder from release to release. See Android AlarmManager setExact() is not exact. There could be two ways to solve this for your case:
you start an activity, which starts the service (as starting an Activity seems to work for you)
you use either setExactAnd... or setAlarmClock. setAlarmClock also triggers in the new "doze" mode, see https://stackoverflow.com/a/47049705/1587329.
Another way would be to re-think why and if you really need this... or if a JobScheduler could not fit your purpose more easily.
add replace your line with this line :
alarmmanager.setRepeating(AlarmManager.RTC_WAKEUP,
startTime.getTimeInMillis(),
operation);
it will repeat on specific interval you set in alarm manager
Replace the AlarmManager with this code:
alarmManager.setRepeating(AlarmManager.RTC,
timeMills,
AlarmManager.INTERVAL_DAY,
pendingIntent);
Worked for me.
HERE IS a DETAILED ANSWER check link in the bottom for more details.
Hope this will help. Your issue can be probably related to android versions too so do check the link for more details
app gets an instance of the AlarmManager and sets an alarm using a PendingIntent. More on usage and setting alarms is coming in the next section. The AlarmManager is the app side interface to the backing AlarmManagerService. It abstracts the details of the Binder interface, used to communicate with the system process (system_server) hosting the AlarmManagerService. These two components manage the alarm(s) the app has set and will send the PendingIntent correctly. This manager/service architecture is used throughout Android framework and is done for security and isolation purposes. The system_server process is running with privileges which normal apps do not have. If you are unfamiliar with Android’s use of permissions, see this article for more details on app processes and user IDs. These extra permissions are what allows system_server to access the underlying kernel alarm driver. The alarm driver is what manages setting alarms to wake up the device regardless of the sleep state of the SoC.
When the alarm is triggered the device is awakened (if asleep) and the AlarmManagerService is notified of an alarm expiring. It will then send the PendingIntent accordingly. This will cause the appropriate component within MyApp to be activated. If MyApp has not been started or its process is not cached, it will be started so the component can be activated.
basic usage will be as
public class MyActivity extends Activity {
...
private AlarmManager mAlarmMgr;
...
public void onCreate(Bundle savedInstance) {
...
mAlarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
...
}
...
}
let’s create a PendingIntent for our MyActivity using the component name.
Intent alarmIntent = new Intent(context, MyActivity.class);
PendingIntent pend = PendingIntent.getActivity(context,
0,
alarmIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Now that we have our PendingIntent and the AlarmManager, we can set our alarm so our Activity is triggered when the alarm has expired. To do this, we need to figure out when we want our alarm to go off and whether it should wake up the device or just be delivered the next time the device is awakened. Remember, we have two different ways of specifying time for our alarms: elapsed time or calendar (RTC) time. So our options are ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC or RTC_WAKEUP. The _WAKEUP variants are our “aggressive” alarms where we want the device to come out of low power to call our app back. For our sample app, let’s set this up in a custom BroadcastReceiver and have it trigger our Activity about 30 seconds after the device is booted
public class MyBootReceiver extends BroadcastReceiver {
public void onReceive(Context, context, Intent intent) {
...
AlarmManager alarmMgr =
(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
long wakeTime = SystemClock.elapsedRealtime() + 30000;
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeTime, pend);
}
}
Now when our device boots and the BOOT_COMPLETED broadcast is sent, our app’s process will be started and our receiver will set an alarm to trigger our Activity to be launched about 30 seconds later. Note that on Android 3.1 devices or newer, you must first manually launch your app before the BOOT_COMPLETED.
CREDIT GOES to writer of this BLOG
if you want to set the repeated alarm using SetExact you are bound to stop all other pending intents on the same time check this link for that here are many examples of how to do it! again credit goes to this writer

Do i need to use broadcast with alarm manager?

i'm creating an alarm application, and this is the method to run the alarm :
public void startAlarm(int minuteToStart)
{
Toast.makeText(context, "Alarm Start in " + formatTime(minuteToStart), Toast.LENGTH_SHORT).show();
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, minuteToStart);
Intent intent = new Intent(context, AlarmActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, idPendingIntent, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
}
And it run this activity after given specific time:
public class AlarmActivity extends Activity {
......
}
It works, but i see people are using BroadcastReceiver, am i doing it wrong? should i use BroadcastReceiver too? I've been searching about BroadcastReceiver but i don't get what difference it will make with my application.
Thanks.
In the general case, A--C's answer would be correct.
However, you are using RTC_WAKEUP as the alarm type. The only guarantee that we have with _WAKEUP alarms is if we use a BroadcastReceiver, then Android will ensure that the device will stay awake long enough for us to execute onReceive(). Any other type of PendingIntent -- activity or service -- has no guarantee, and it is very possible for the device to fall back asleep before the startActivity() or startService() actually occurs.
You can use AlarmManager with whatever PendingIntent is capable of (Activity, service, Receiver), though, it is usually used with Receivers - taks executing in the future usually are small and don't need an Activity to run in since the user doesn't need something popping up.
A Receiver isn't an Activity, so it does not have a UI and it has a processing time limit of about 10 seconds, so make sure to be quick. If you require a UI to be shown at a specific time, stick with an Activity, but usually this isn't the case unless it's something like an Alarm Clock app that the user has to see). If you have something like a small behind the scenes operation, go for a Receiver. The Receiver's onReceive() gets a Context passed to it so it can do anything a Context can.
Just keep in mind you will have to change the PendingIntent.getActivity() call to whatever else you decide to use if it's not going to be an Activity.
So it all depends on what you want to do.
You don't have to use a BroadcastReceiver. It's just generally frowned upon (in most cases) to steal focus and launch an Activity from the background without user interaction. There are certainly valid use cases though. If you intend to launch an Activity immediately anyway, doing that directly instead of via BroadcastReceiver is perfectly valid.

Android Alarm and service trigger

Couple of question on Alarm registration and starting service on trigger.
If an alarm is set at couple of mins ahead of current time and then if phone is made switch off, will the alarm trigger on next phone switch on after the schedule time passed?
How to cancel / update pending intent in service? How to get request code in startCommand() method of service?
Will there be a multiple instances of service created if the alarm is triggered after every 10 seconds?
If "switch off" means full power down and not just "once shortly press power button to turn screen off" the answer is "no"
I think you can't get request code at all. As the documentation on getService states, the requestCode field is "currently not used". You should pass all your data with Intent (third arg of getService).
Will not. See http://developer.android.com/reference/android/content/Context.html#startService(android.content.Intent)
Every call to this method will result in a corresponding call to the target service's onStartCommand(Intent, int, int) method
Store the time of the alarm in SharedPreferences. Then register a receiver for android.intent.action.BOOT_COMPLETED (remembering to add a permission for android.permission.RECEIVE_BOOT_COMPLETED to your manifest), and then in the receiver, which will execute on startup, you can see if the alarm's in SharedPreferences, and if so you can reset it if it hasn't passed yet, or decide what to do if the time has already passed.
See problem with cancel the alarm manager pending intent
No. The service's onCreate will only be called once. Its onStart and onStartCommand will be called each time.
From my own app that I'm developing, if an alarm is set for a time when the phone is turned off, it has been executed on the next phone on/boot. That is without a receiver for BOOT_COMPLETED being present. I am unsure if this is expected behaviour or not, or whether it is consistent over phone variants.
I believe if you wish to have your alarm execute the intent at its specified time, you need to use a getBroadcast PendingIntent with a WakeLock as other variants of PendingIntent do not guarantee that phone will remain awake long-enough before it shuts down again. This is information from another post here by CommonsWare, that I will try to find and link to.
I believe you can remove the pendingintent sent to the alarm manager using, for example, a function like:
public void unregisterEvent(PendingIntent sender) { ((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).cancel(sender);
}
where the PendingIntent has been created exactly as the original intent you are trying to remove. You can update it by supplying the correct id along with a new PendingIntent when calling AlarmManager again:
AlarmManager am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
This is what I use to create/rebuild the PendingIntent:
PendingIntent.getService(this, uniqueIndexToIntent, theIntentItself, PendingIntent.FLAG_UPDATE_CURRENT);
The flag will update the intent if it already exists, or will create a new one otherwise.
I don't think it will. However, I'd recommend having your Service call stopSelf() once it has finished doing its work, so that battery usage is minimised. No need to have it running if it has nothing to do!

Android long running service with alarm manager and inner broadcast receiver

I have a Service that uses a custom Connection class (extends thread) to a hardware controller. When the User prefers, I wish to maintain this connection on a permanent basis. I already have the code to handle when the Android device loses its internet connection, switches between wi-fi, etc.
In order to stay connected, the controller requires that you speak to it within every 5 minutes. I currently, within the Connection class start a thread that runs in a while(), and checks the system time and the last time it communicated, and when > 4 minutes it requests a status. For some reason, at different times the communication doesn't occur in time. i.e., occurs after 5 minutes. The Service doesn't die, as far as I can tell but the "Ping" to the controller is late. This doesn't happen when I have the phone plugged into the charger (or debugger). Additionally, the behavior is the same when I move the Service to the foreground.
Does the phone slow down it's processor when it goes to sleep?
Is there a better way?
I'm thinking it's the AlarmManger, but I'm having trouble getting it to work with an inner-class, within the Service. I tried using the API demos as a starting point, but I can't seem to figure out how to get the Broadcast receiver registered. I am trying to register the receiver programmatically, with no changes to the manifest.
public class DeviceConnectionService extends Service {
#Override
public void onCreate() {
Intent intent = new Intent(this, PingConnection.class);
intent.setAction("KEEP_CONNECTION_ALIVE");
PendingIntent sender = PendingIntent.getBroadcast(this,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// We want the alarm to go off 30 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
firstTime += 15*1000;
// Schedule the alarm!
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, 15*1000, sender);
// register to listen to the Alarm Manager
if (mPingConnectionReceiver == null) {
mPingConnectionReceiver = new PingConnection();
getApplicationContext().registerReceiver(mPingConnectionReceiver,
new IntentFilter("KEEP_CONNECTION_ALIVE"));
}
}
// ...
public class PingConnection extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (dBug) Log.i("PingConnection", "Pinging Controller");
// do real work here
}
}
}
Does the phone slow down it's processor when it goes to sleep?
The phone shuts down its processor when it goes to sleep. That is the definition of "sleep".
I'm thinking it's the AlarmManger, but I'm having trouble getting it to work with an inner-class, within the Service. I tried using the API demos as a starting point, but I can't seem to figure out how to get the Broadcast receiver registered. I am trying to register the receiver programatically, with no changes to the manifest.
That is an unusual approach for AlarmManager. That being said, since you declined to describe "having trouble" in any detail, it is difficult to help you.
Get rid of getApplicationContext() (you don't need it and really don't want it in this case). I would register the receiver before touching AlarmManager. Before you go to production, please choose an action name that has your package name in it (e.g., com.something.myapp.KEEP_CONNECTION_ALIVE).
Beyond that, check LogCat for warnings.
UPDATE
In your LogCat, you should have a warning from AlarmManager complaining about not being able to talk to your BroadcastReceiver.
Replace:
Intent intent = new Intent(this, PingConnection.class);
intent.setAction("KEEP_CONNECTION_ALIVE");
with:
Intent intent = new Intent("KEEP_CONNECTION_ALIVE");
and you may have better luck.
you can't register AlarmManager in a Service.
All you can do is declare it as global in the Manifest.xml.
You can start the alarm from service in this way, by declaring it in Manifest.xml
If you have a remote service and you close the launcher activity, the AlarmManager will still run, but don't forget to stop it on onDestroy() method of the service.
I've tried to register only in the Service the AlarmManager as I didn't used it for the main activity, but no success!
It didn't work as registering as a normal BroadCastReceiver.
that's how the things are, you have to declare it in Manifest.xml as global
I know it's late, but maybe it's useful for someone else.
You can register it, the problem is when the Intent tries to call it.
Instead of calling it like this:
Intent intent = new Intent(this, PingConnection.class);
Create an empty intent and add an action you are going to listen to:
Intent intent = new Intent();
intent.setAction("value you want to register");
Then create the pending intent and send the broadcast like you have it.
Create an attribute for the receiver so you can access it in the whole class and unregister if necessary (if the pendingIntent is also an attribute you can unregister any time):
private PingConnection pingConnection = new PingConnection();
Register it like this:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("the value you used before");
getApplicationContext().registerReceiver(pingConnection, filter);
Now you won't get any errors, and the class is not static, and it's an inner class.

onAlarm fired receiver

I want to create a broadcast receiver that will get notified when an alarm is started.
For example I set the alarm to 10 am and I go to sleep, then when the alarm is fired I want to have an receiver that will be notified.
Is it possible to do this ?, is there any intent that is fired on alarm start ?
For setting alarm use Alarm-manager class. You can set alarm using pending intent and using calendar you can set the time. Check the following code, in this AlarmReceiever is broadcast receiver which receives intent from pending intent at specific time that you can set in set method as second parameter .
Intent alaram=new Intent(FirstActivity.this,AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(FirstActivity.this, 0, alaram,PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(),pendingIntent);
//cal.setTimeInMillis(System.currentTimeMillis());
cant you use pendingIntent too!! just saying
It appears that there is no standart alarm used by alarm applications. So either you have to look up used alarm in your logs and use it ( this will be alarm application dependent, and
surely not portable ) or just use alarm manager and schedule your own alarm

Categories

Resources