I am trying to develop an app where it locks down the Activity and starts a service which will set an AlarmManager to setRepeating() trigger to another Service which will send a SMS containing the phone's location.
I have achieved the periodic sending of the SMS. However, I now want to cancel the AlarmManager when I finish() the lockdown activity. Please help me as I cant seem to understand the approach to address this.
Program flow:
Lockscreen (Activity trigger Service) --> AlarmManager (in Service class) --> Coordinate (Another Service that send sms)
Call cancel() on AlarmManager with an equivalent PendingIntent to the one you used to register the alarm in the first place. By "equivalent" I mean that it is the same type of PendingIntent (activity, service, broadcast) and wraps an Intent that is the same on all routing elements (component, data, MIME type, categories).
Related
In one of the exemptions of the "cannot start foreground service from background" restriction, the doc mentions:
Your app invokes an exact alarm to complete an action that the user
requests.
Does this mean that the usage scenario below can work?
Use AlarmManager.setAlarmClock to schedule an exact alarm to trigger at time A. The alarm carries a pendingIntent that targets a registered broadcast receiver.
Time A hits, the receiver gets the intent.
In the receiver OnCreate method, we attempt to startForegroundServicewhich involves displaying a sticky notification and playing custom music with MediaPlayer.
I have implemented and tested this and it appears to be working, so I assume this is a valid use case.
I'm currently working on an app that handles alarms. I have reach the point where I can set the alarms using the AlarmManager and everything seems to work fine, but.. In all the examples that I found, and even in the Android official docs, I have seen people using a BroadcastReceiver for the PendingIntent, and then, calling an activity or whatever they need when the alarm fires. However, I have try to just pass a simple activity to the PendingIntent for the AlarmManager like this:
Intent intent = new Intent (getApplicationContext(), AlarmActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity (this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set (AlarmManager.RTC_WAKEUP, timeToTrigger.getTimeInMillis(), pendingIntent);
And after testing alarms in several contexts (app in foreground, app not running, etc..) I found that the activity is always been called correctly.
So, my doubt is as simple as: Why do people use a BroadcastReceiver and in the onReceive method call an activity if you can just simple call the activity directly?
Android frowns on this behaviour. You shouldn't interrupt the user if he is doing something else. This is why you don't want to launch an Activity from AlarmManager. Usually, you launch a BroadcastReceiver, which, if it wants to get the user's attention, will post a Notification. The user can then open the app via the Notification whenever he wants to.
Also, often you just want to perform some background process (like fetching data from a server, or updating some statistics), which doesn't require any user-interaction. In this case you would also launch a BroadcastReceiver or Service and not an Activity.
Starting with Android 10 there are more restrictions about background apps launching activities. Therefore, with current versions of Android it has become more difficult to do this. See https://developer.android.com/guide/components/activities/background-starts
So basically, even though it does work, it is not considered "respecting the user" and it probably won't work in the future.
I am starting a foreground service from a fragment which gets destroyed after call to startService(), which is a reason I can't use ResultReceiver or Messanger. So the option remains PendingIntent. How can I communicate between foreground service(hosted in different process) from any activity/fragment using PendingIntent?
You have two separate issues:
How do you get data from the service process to the UI process?
How do you get the data from whatever you did for #1 to whatever portion of the UI needs that data?
There are any number of solutions for #1: PendingIntent, ResultReceiver, Messenger, AIDL-defined callback for a bound service connection, etc. #2 then mostly is a matter of using an event bus or something similar to alert all relevant Java objects about the new data.
So, for example, here is an off-the-cuff recipe for using a PendingIntent for this:
Implement a BroadcastReceiver or Service in your activity process, registered in the manifest, but with no <intent-filter>
As part of calling startService(), create a PendingIntent using its getBroadcast() or getService() factory method, with an Intent that identifies your BroadcastReceiver or Service, and put that PendingIntent in an extra for the Intent used with startService()
Your service in the other process, when it has data to deliver to the activity process, calls send() on the PendingIntent, including an Intent with data to fill into the broadcast or service request
Your BroadcastReceiver or Service from step #1 takes the Intent delivered to it and uses an event bus to let the rest of your activity process know about whatever happened, also handling the case where nothing in the activity process is registered for the event (e.g., raise a Notification if all activities were destroyed)
I'm creating an app that, after receiving a text from a certain number, starts a repeating alarm using AlarmManager. The AlarmReciever plays an alarm sound for thirty seconds and then the alarm repeats every five minutes. I want to cancel the AlarmManager when the app is closed and restarted by the user but I have to use the same instance of the alarmIntent to cancel it.
I have to use the same instance of the alarmIntent to cancel it.
No, you have to use an equivalent PendingIntent to cancel it. By "equivalent", I mean:
It is the same operation (e.g., activity, service, broadcast)
It has the same request code (2nd parameter to methods like getActivity())
It has an equivalent Intent
By "equivalent Intent", I mean that all the routing information is the same (component, action, data, MIME type, categories). Extras do not matter.
You need to hold onto enough information in a persistent data store (e.g., file) to be able to create an equivalent PendingIntent to pass to cancel() on AlarmManager.
I need help in my android app development.
It goes something like this,
I will be having two separate applications (2 projects). In one application, i have to start a repeating alarm and in the other application i have to cancel the same alarm that was started in the first application.
The Android documentation says, the same pending intent and the intent object that was used to start the alarm
should be used the cancel the alarm.
So in this scenario, the pending intent and the intent object that was used to start the alarm will belong to application1 so i cannot used the same objects in application2
How do I proceed?
In summary -
The problem is, I need to start a repeating alarm from one application and i have to cancel the same alarm from another application.
Can this be done. If so, How?
Thanks in advance.
ifreeman
It is not that straightforward. Only original activity can cancel the alarm.
So I think you can configure a custom broadcast. When the second activity needs to cancel an alarm it will send this broadcast. The first activity will be listening to the broadcast and cancel the appropriate alarm on receiving it.
I guess you can do. Alarms are considered as same if intents passed to them via pending intent are same. filterEquals method of Intent class defins if intents are same or not. If intents are same then alarms are same so u can cancel that alarm. Check once.