I am making an alarm, and service is started by the alarm. I want services to receive Extra data so with googling I set the flag as Intent.FILL_IN_DATA. Below is my code.(Only important part is shown)
(I have several alarm mode, and different services are called)
public static void setAlarm(Context mContext, int mode){
if(mode==A){
intent = new Intent(mContext, AService.class);
}
else{
intent = new Intent(mContext, BService.class);
intent.putExtra(NOTI_MODE, mode);
}
PendingIntent pIntent = PendingIntent.getService(mContext, 0, intent,Intent.FILL_IN_DATA);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
Log.d("set alarm","alarm 4.4");
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pIntent);
} else {
Log.d("set alarm","alarm 4.4 under");
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pIntent);
}
}
public static void cancelAlarm(Context mContext){
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
PendingIntent pIntent = PendingIntent.getService(mContext, 0, new Intent(mContext, AService.class),Intent.FILL_IN_DATA);
alarmManager.cancel(pIntent);
pIntent = PendingIntent.getService(mContext, 0, new Intent(mContext, BService.class),Intent.FILL_IN_DATA);
alarmManager.cancel(pIntent);
}
service side code(edit: this code is in BService class. AService does not need to receive Extras.)
public int onStartCommand(Intent intent, int flags, int startId) {
int notiMode=intent.getIntExtra(AlarmManagerHelper.NOTI_MODE, -1);
}
However, the result is always -1, which means no Extras is being received.
What is the problem with my code? I'm googling for hours and no hope.
Please help if you have any ideas.
Thanks in advance.
EDIT: setAlarm method is in
public class AlarmManagerHelper extends BroadcastReceiver{} class.
and below is from AndroidManifest
<receiver android:name="com.example.test.AlarmManagerHelper" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
When I use
pIntent = PendingIntent.getService(mContext, 0, new Intent(mContext, BService.class), 0);
instead of
pIntent = PendingIntent.getService(mContext, 0, new Intent(mContext, BService.class),Intent.FILL_IN_DATA);
at cancelAlarm(), service gets Extras all right (but the alarm does not cancel of course)
I don't get why setAlarm() does not work when I change cancelAlarm()..
I found the solution. Quite embarrassing.. I should have searched more for myself before posting the question...
Changed Intent.FILL_IN_DATA to PendingIntent.FLAG_UPDATE_CURRENT and now it works like charm.
Does not know why, but if you are suffering from same problem, please try this solution :)
According to the code you posted, you have two services (AService and BService).
I am guessing that the code snippet you are sharing is for your AService?
I think the top part of your setAlarm method should be:
public static void setAlarm(Context mContext, int mode)
{
if(mode==A)
{
intent = new Intent(mContext, AService.class);
// NOTE: Add this line!
intent.putExtra(NOTI_MODE, mode);
}
else
{
intent = new Intent(mContext, BService.class);
intent.putExtra(NOTI_MODE, mode);
}
// snipped rest of code in this method
}
Related
I used AlarmManager to set time and expect to do some work in the future. Almost case it work well without problem. But sometimes (just sometimes), the alarm not fired. It is difficult to reproduce the issue and I still do not know the reason.
I got this issue on several OS version : 4.4, 5.1, 6.0, 6.1, 7.0.
I already used WakefulBroadcastReceiver to start a service with Wakelock, but the issue still happen.
Below is my code to schedule a alarm.
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
alarmIntent.putExtra("todo_id", myTodo.getId());
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, myTodo.getId(), alarmIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(calendar.getTimeInMillis(), pendingIntent);
alarmManager.setAlarmClock(alarmClockInfo, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
public class AlarmReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
LogUtil.debug("onReceive()");
if (null != intent.getExtras()) {
int id = intent.getIntExtra("todo_id", -1);
if (id != -1) {
Intent myIntent = new Intent(context, AlarmService.class);
myIntent.putExtra("todo_id", id);
LogUtil.debug("Receiver receive todo id: "+id );
startWakefulService(context, myIntent);
}
}
}
}
public class AlarmService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtil.debug("Service onStartCommand");
int id = intent.getIntExtra("todo_id", -1);
LogUtil.debug("Service receive todo id: " + id);
// do some stuff here
AlarmReceiver.completeWakefulIntent(intent);
return START_REDELIVER_INTENT;
}
Does anyone have the same issue like me ? And what is your solution ?
Maybe this issue come from Android SDK, they made AlarmManager work unstable.
I had the same issue , i solved this issue by doing all my logic in AlarmReceiver. I was also starting service in receiver which hold my alarm logic. But once i move my code into alarm receiver it works fine. Mine issue was i wasn't ending my service , it kept on running and causing some issue or might be other reasons but it solved my issue. You should try and let me know if this help.
In my android application I have a "global" application class and inside it, among others, I have a static BlockingQueue in which I store information. When the queue is full I flush it to file. I have multiple producers, Services, BroadcastReceivers and everything works fine. Now I have to add an alarm that every 30 minutes triggers a PendingIntent from which I have to write to this BlockingQueue and this doesn't work! I see that the appropriate functions are called but the data is not written. If I Log.d() it before blockingQueue.put() I can see the data and then it get lost. I do the same procedure from everywhere in my app and it only does not work from the BroadcastReceiver of the PendingIntent of the Alarm. For sure I'm missing something. What can I do?
Here's how I trigger the Alarm from a Service (and it works):
alarmNotificationIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, QuestionnaireNotificationReceiver.class), 0);
if(alarmNotificationIntent!=null) {
if (alarmManager != null) {
if (iLogApplication.isAtLeastMarshmallow()) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + Constants.NOTIFICATION_INTERVAL, alarmNotificationIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + Constants.NOTIFICATION_INTERVAL, alarmNotificationIntent);
}
}
}
And this is the BroadcastReceiver:
public class QuestionnaireNotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(context.toString(), "Questionnaire notification");
//this method does blockingQueue.put(answer.toString());
iLogApplication.persistInMemoryAnswerQuestionnaireEvent(new Answer(new Question(666)));
System.out.println(iLogApplication.questionnaire.toString());
SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.PACKAGE_NAME, Context.MODE_PRIVATE);
Intent notificationIntent = new Intent(context, NotificationActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context, (int) System.currentTimeMillis(), notificationIntent, 0);
iLogApplication.questionnaireBuilder.setContentTitle("Nuova domanda disponibile")
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_notification_bar)
.setAutoCancel(false)
.setOngoing(true);
String notificationText = "Hai %d domand%c a cui rispondere";
if (iLogApplication.questionnaireBuilder != null) {
iLogApplication.questionnaireBuilder.setWhen(System.currentTimeMillis());
if(iLogApplication.questionnaire.getNumberOfQuestions()>2) {
iLogApplication.questionnaireBuilder.setContentText(String.format(notificationText, iLogApplication.questionnaire.getNumberOfQuestions(), 'e'));
}
else {
iLogApplication.questionnaireBuilder.setContentText(String.format(notificationText, iLogApplication.questionnaire.getNumberOfQuestions(), 'a'));
}
}
if (iLogApplication.notificationManager != null) {
iLogApplication.notificationManager.notify(Constants.QUESTIONNAIRENOTIFICATIONID, iLogApplication.questionnaireBuilder.build());
}
PendingIntent alarmNotificationIntent = PendingIntent.getBroadcast(context, 0, new Intent(context, QuestionnaireNotificationReceiver.class), 0);
if(alarmNotificationIntent!=null) {
if(iLogApplication.alarmManager!=null) {
if (iLogApplication.isAtLeastMarshmallow()) {
iLogApplication.alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+ Constants.NOTIFICATION_INTERVAL, alarmNotificationIntent);
} else {
iLogApplication.alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+ Constants.NOTIFICATION_INTERVAL, alarmNotificationIntent);
}
}
}
}
}
Since I want my alarm to work also in Marshmallow Doze mode I have to use setExactAndAllowWhileIdle() and recall the method every time the Broadcast is triggered.
The problem was the PendingIntent. In the manifest I declared it like this:
<receiver android:process=":remote" android:name=".broadcastreceivers.QuestionnaireNotificationRunnable"></receiver>
the flag android:process=":remote" forces it to run on a different process. By removing it everything started working perfectly.
I'm writing an application with multiple alarms and I want to have an option to cancel them. I'm using AlarmManager and PendingIntent. My problem is that when I want to cancel an alarm, getBroadcast don't find a PendingIntent matching the criteria.
private void turnOnMorningRemider()
{
long time = System.currentTimeMillis() + 60 * 45;
Intent tmpIntent = new Intent(this, AlarmPopUpDialog.class);
tmpIntent.putExtra(getString(R.string.alarm_time_of_day), AlarmPopUpDialog.REQUEST_CODE_MORNING);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntent(tmpIntent);
// Gets a PendingIntent containing the entire back stack
morningPendingIntent = stackBuilder.getPendingIntent(AlarmPopUpDialog.REQUEST_CODE_MORNING, PendingIntent.FLAG_ONE_SHOT);
//set the alarm for particular time
alarmManager.set(AlarmManager.RTC_WAKEUP, time, morningPendingIntent);
Toast.makeText(this, "Alarm is on.", Toast.LENGTH_LONG).show();
}
To cancel alarm I use:
private void turnOffMorningReminder()
{
Intent tmpIntent = new Intent(this, AlarmPopUpDialog.class);
PendingIntent pi = PendingIntent.getBroadcast(this, AlarmPopUpDialog.REQUEST_CODE_MORNING,
tmpIntent, PendingIntent.FLAG_NO_CREATE);
if (pi != null)
{
alarmManager.cancel(pi);
Toast.makeText(this, "Alarm is off.", Toast.LENGTH_LONG).show();
}
}
The pi variable is always null, so alarm starts ringing.
The next problem is, when I try to create PendingIntent with getBroadcast (instead of stack builder) my alarm never activates.
morningPendingIntent = PendingIntent.getBroadcast(this, AlarmPopUpDialog.REQUEST_CODE_MORNING, tmpIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Is using the stack builder the reason why i can't find the intent?
I feel stupid. My problem was that my AlarmPopUpDialog extended Activity not BroadcastReceiver class. When I added a class that extened BroadcastReceiver in the middle everything started to work.
morningPendingIntent = PendingIntent.getBroadcast(this, AlarmBrodcastReceiver.REQUEST_CODE_MORNING, tmpIntent, PendingIntent.FLAG_UPDATE_CURRENT);
and
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Intent i = new Intent(context, AlarmPopUpDialog.class );
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtras(intent);
context.startActivity(i);
}
}
I hope that this answer will help the next poor guy.
this is my code for menage a single notification:
myActivity.java
public class myActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylayout);
cal = Calendar.getInstance();
// it is set to 10.30
cal.set(Calendar.HOUR, 10);
cal.set(Calendar.MINUTE, 30);
cal.set(Calendar.SECOND, 0);
long start = cal.getTimeInMillis();
if(cal.before(Calendar.getInstance())) {
start += AlarmManager.INTERVAL_FIFTEEN_MINUTES;
}
Intent mainIntent = new Intent(this, myReceiver.class);
pIntent = PendingIntent.getBroadcast(this, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager myAlarm = (AlarmManager)getSystemService(ALARM_SERVICE);
myAlarm.setRepeating(AlarmManager.RTC_WAKEUP, start, AlarmManager.INTERVAL_FIFTEEN_MINUTES, pIntent);
}
}
myReceiver.java
public class myReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context c, Intent i) {
Intent myService1 = new Intent(c, myAlarmService.class);
c.startService(myService1);
}
}
myAlarmService.java
public class myAlarmService extends Service {
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#SuppressWarnings("deprecation")
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
displayNotification();
}
#Override
public void onDestroy() {
super.onDestroy();
}
public void displayNotification() {
Intent mainIntent = new Intent(this, myActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager nm = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Notification.Builder(this);
builder.setContentIntent(pIntent)
.setAutoCancel(true)
.setSmallIcon(R.drawable.ic_noti)
.setTicker(getString(R.string.notifmsg))
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(R.string.notifmsg));
nm.notify(0, builder.build());
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK" />
...
...
...
<service android:name=".myAlarmService" android:enabled="true" />
<receiver android:name=".myReceiver"/>
IF the time has NOT past yet everything works perfectly. The notification appears when it must appear.
BUT if the time HAS past (let's assume it is 10.31 AM) the notification fires every time... when I close and re-open the app, when I click on the notification... it has a really strange behavior.
I can't figure out what's wrong in it. Can you help me please (and explain why, if you find a solution), thanks in advance :)
Place display notification inside an if statement , such that compare the current time with the notification set time and if the current time is before the set time then display notification, else do nothing.
int temp = calTemp.getTime().compareTo(calendar.getTime());
if(temp > 0){
}else{
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(),
pendingIntent1);
}
here calTemp gives current time and calender gives the time i want to fire the alarm. So according to above code if the time has already past then the notification will not fire for sure .
Hi I've had the same problem and found a solution in this SO post, basically the idea is to rely on AlarmManager, Receiver but avoid usage of Service.
Since you are using the Service just to build and display the notification you may find useful my approach.
Let me know.
How can I 'clean' values from extra intent?
Activity:
#Override
public void onCreate(Bundle savedInstanceState) {
...
Intent intent = new Intent(this, MyBroadcastReceiver .class);
intent.putExtra("valueOne", "valOne");
intent.putExtra("valueTwo", true);
intent.putExtra("valueThree", 1);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this.getApplicationContext(), 234324243, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (5 * 1000), pendingIntent);
...
}
BroadcastReceiver:
#Override
public void onReceive(Context context, Intent intent) {
...
String valueOne= intent.getStringExtra("valueOne");
Boolean valueTwo= intent.getBooleanExtra("valueTwo", false);
Integer valueThree= intent.getIntExtra("valueThree", 0);
// Log.i("info", valueOne) >> valOne
// Log.i("info", valueTwo.toString()) >> false
// Log.i("info", valueThree.toString()) >> 1
...
}
If I change value in Activity and run application again, I get same values like in first start. I try delete app from my phone/virtual machine, clean project, but problem stay :(
Anybody help me?
In the Pending Intent declaration try to set the following flag:
PendingIntent.FLAG_UPDATE_CURRENT
In your case it should be the following:
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this.getApplicationContext(), 234324243, intent, PendingIntent.FLAG_UPDATE_CURRENT);
First, i suggest you to format your code here. So that people here will be glad to read your problem code. Your code list above does NOT register any BroadcastReceiver to the system. You'd better to check out ApiDemo for more details.
And Also See this one