I want to make it so that a user will receive a push notification every 24 hours after he completes an action within my android game. Push notifications are working with Parse, but I don't know how to delay 24 hours, and then send the push. The Parse documentation mentions background jobs, but since those time out after 15 minutes, I don't think I can use those. Is there something I'm missing, or another option I can use?
Instead of push notification, you can depend on In-app notification, for that you have to set an AlarmManager to trigger the notification after 24 hour, and on receive of alarm you can initialize another alarm that has to be triggered after 24 hours.
ex:
public static void startAlarm(Context context) {
Calendar nextAlarmTime = getNextAlarmTime(context);
if (nextAlarmTime != null) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intentAlarm = new Intent(context, AlarmReceiver.class);
alarmManager.set(AlarmManager.RTC_WAKEUP, nextAlarmTime.getTimeInMillis(), PendingIntent.getBroadcast(context, 1, intentAlarm, PendingIntent.FLAG_CANCEL_CURRENT));
}
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
private static final String TAG =
AlarmReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
initNotificationMessage(context);
scheduleNextNotification(context);
}
}
and if you wish to change the notification messages then you have to make an api call to your server just before showing the notification,and receive the message from server and show it as notification
and if you insisted to use push notification, it is better to keep the logic in client side than using cron job or any similar mechanism, that means use the same logic as mentioned above and request your server to send a push notification to your device.
Related
I'm writing my android application, which should always show a notification every day at 10:00 AM, no matter what. I use an alarm service to fire notifications at a specific time.
I set notifications to fire in two cases:
when I open the app, I set the alarm service to fire at the nearest 10:00 AM
when I receive notifications, I set the alarm service to fire the next day at 10:00 AM
The problem is: When the interval between the moment when I set alarm service and the actual alarm is greater than approx 12 hours, I just don't receive that notification. If the interval is smaller - I do. But I checked the logs, the alarm service is scheduled properly and for the correct time no matter how I set notifications.
I expect the problem is in the battery optimizer, but I don't know how to verify (and fix) that.
What I tried
In Android I've added my app to exceptions, allowing it to run in the background.
Tested on Huawei P30 Pro, Android 10.
Attaching the code how notifications are scheduled
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// display notification
NotificationController.scheduleNextNotification(context);
}
}
public class NotificationController {
public static void scheduleNextNotification(Context context) {
Intent myIntent = new Intent(context, AlarmBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
long notificationTime = getNotificationTime(new Date());
int alarmType = AlarmManager.RTC_WAKEUP;
alarmManager.setExactAndAllowWhileIdle(alarmType, notificationTime, pendingIntent);
}
}
I am developing an android app which shows a notification every 12 hour if the time is saved in the database. So everytime a data is entered or edited in the database ,I cancel the current alarmmanager and start a fresh new one so that I dont miss one. Also on reboot I have called the alarmmanager. On the broadcast receiver, the database is checked for entry and if found a notification is set and the app is opened automatically.
So when I test the app by changing the date manually,the app works as expected.Also on reboot the app works.But if I keep the app idle for nearly 14 hours,the notification is not set ,but if I open the app and suspend it the notification is set after that.
This is how I call the alarmmanager.
Intent alarmintent = new Intent(context, package.Alarm_Manager.class);
alarmintent.putExtra("note","Notify");
sender = PendingIntent.getBroadcast(context , 0 , alarmintent , PendingIntent.FLAG_CANCEL_CURRENT | Intent.FILL_IN_DATA);
alarm_manger = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarm_manger.cancel(sender);
Calendar cal = Calendar.getInstance();
long now = cal.getTimeInMillis();
alarmintent = new Intent(context, package.Alarm_Manager.class);
alarmintent.putExtra("note","Notification");
sender = PendingIntent.getBroadcast(context , 0 , alarmintent , PendingIntent.FLAG_CANCEL_CURRENT | Intent.FILL_IN_DATA);
alarm_manger = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm_manger.setRepeating(AlarmManager.RTC_WAKEUP, now, AlarmManager.INTERVAL_HALF_DAY, sender);
This is the broadcast receiver
#Override
public void onReceive(Context context, Intent intent)
{
NotificationManager manger = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Calendar cal = Calendar.getInstance();
date = (int)(cal.getTimeInMillis()/1000);
Notification notification = new Notification(R.drawable.vlcsnap_396460 , "Notify" , System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, 0);
notification.setLatestEventInfo(context, "App", "Notify" , contentIntent);
notification.flags = Notification.FLAG_INSISTENT;
manger.notify( 0 , notification);
}
You don't need to call alarm_manager.cancel(sender); if you set the PendingIntent.FLAG_CANCEL_CURRENT.
Your call to
alarm_manger.setRepeating(AlarmManager.RTC_WAKEUP, now, AlarmManager.INTERVAL_HALF_DAY, sender);
will trigger the alarm right away, since the now is already passed when you set the alarm.
I suggest you use
now + DateUtils.HOUR_IN_MILLIS / 2
for the triggerAtMillis parameter
Did you tried to schedule it for smaller interval? Does it get triggered ?
After having seen your Alarm_Manager code, I think it is illegal to do this in your BroadcastReceiver object directly. Quote:
If this BroadcastReceiver was launched through a tag, then the object is no longer alive after returning from this function.
I believe there is no other way than to create a Service which is informed by your BroadcastReceiver, and make sure that the Service calls setLatestEventInfo() with itself (this) as the Context.
The reason why your asynchronous Broadcast fails while it works when your app is running is probably that the Context provided to the BroadcastReceiver lives only for the duration of the call to the BroadcastReceiver when your app does not run. So the Notification service, which only runs after your BroadcastReceiver has died along with the temporary context, is missing a valid context.
When your app runs, the Broadcast probably comes with your Activity or Application object as Context, and this is still vaild when the Notification manager runs.
Hope this helps.
Update: An `IntentService`` will do. You don't want a full time Service for that.
Update 2: Some snippets.
<service android:name=".MyIntentService" android:label="#string/my_intent_service_name" />
public final class MyIntentService extends IntentService {
public MyIntentService() {
super("service name");
// set any properties you need
}
#Override
public void onCreate() {
super.onCreate();
// do init, e.g. get reference to notification service
}
#Override
protected void onHandleIntent(Intent intent) {
// handle the intent
// ...especially:
notification.setLatestEventInfo(this, "App", "Notify" , contentIntent);
// ...
}
}
public final class MyAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, MyIntentService.class));
}
}
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)
I tried to develop a sample Alarm Application. I searched Google and SC, most of their examples confused. How can I create an alarm application with the following requirements,
In My Home screen i have a button, like "START ALARM", when i click the button a time picker must enable.
I select the time as I wish, once I pick the time, the alarm icon will enabled on widget. (For example if we set the alarm in default mobile Alarm application, the icon will be enabled, that indicates the alarm is set).
When the set time is reached (the time which is set form the TimePicker app), the alarm will beep.
These are my requirements, I finished the first two points, but I'm still struggling on setting the alarm.
Take a look at AlarmManager. And, If you want to use alarm simultaneously you must use Service class for that. And, see below sample code -
public class OnBootReceiver extends BroadcastReceiver {
private static final int PERIOD=300000; // 5 minutes
#Override
public void onReceive(Context context, Intent intent) {
AlarmManager mgr =
(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent i=new Intent(context, OnAlarmReceiver.class);
PendingIntent pi=PendingIntent.getBroadcast(context, 0, i, 0);
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime()+60000, PERIOD, pi);
}
This will repeat the alarm with every 6 Mins. See Scheduling Repeating Alarms document.
when you enable the alarm you have to call inbuilt alarm manager and use the alarmmanager.set to set the alarm time in the manager.
Once the alarm time (in milliseconds) is given to the alarm manager it will send message and you can retrive the message through reciever class
//creating and assigning value to alarm manager class
Intent AlarmIntent = new Intent(MainActivity.this, AlarmReciever.class);
AlarmManager AlmMgr = (AlarmManager)getSystemService(ALARM_SERVICE);
PendingIntent Sender = PendingIntent.getBroadcast(MainActivity.this, 0, AlarmIntent, 0);
AlmMgr.set(AlarmManager.RTC_WAKEUP, Alarm.getTimeInMillis(), Sender);
For recieving the alarm you have to make a new class which extends reciever where in onrecieve you can set the intent to the activity u want to call on alarm time , you can also provide notification.
public class AlarmReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{ //Build pending intent from calling information to display Notification
PendingIntent Sender = PendingIntent.getBroadcast(context, 0, intent, 0);
NotificationManager manager = (NotificationManager)context.getSystemService(android.content.Context.NOTIFICATION_SERVICE);
Notification noti = new Notification(android.R.drawable.stat_notify_more, "Wake up alarm", System.currentTimeMillis());
noti.setLatestEventInfo(context, "My Alarm", "WAKE UP...!!!", Sender);
noti.flags = Notification.FLAG_AUTO_CANCEL;
manager.notify(R.string.app_name, noti);
//intent to call the activity which shows on ringing
Intent myIntent = new Intent(context, Alarmring.class);
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(myIntent);
//display that alarm is ringing
Toast.makeText(context, "Alarm Ringing...!!!", Toast.LENGTH_LONG).show();
}}
If you still get any problem ask again..:)
If you want to make things interesting, you can try to create one without a possibility of dismissing/snoozing. I made this a while ago, you can read about it in this tutorial:
Alarm Application in Android (Tutorial using AlarmManager)
And test the app functionality by downloading this app:
Oversleeper on Google Play
To finish your last point you need to do Date Comparision and use AlaramManager Alaram Doc and again you need to use Service
to compare next date and time. Hope it will helpful for you.
You need to use RingtoneManageror the NotificationManager(to show any text or image to the user for notification at the top of screen), Or you can use MediaPlayerto set to play sound when alarm time is reached. You have to set <receiver> tag in manifest file, that must include a class extending BroadCastReceiver. In the receiver class you can write your code to wake your device up.
I would like to display an alert dialog when the alarm goes off. Here is where i am so far. Im not sure if im doing it right.
#Override
void doTaskWork(Intent intent){
String taskId = intent.getStringExtra(TaskHelper._id);
NotificationManager mgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(this, TaskDetails.class);
notificationIntent.putExtra(TaskHelper._id, taskId);
PendingIntent pi = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
Notification note = new Notification(R.drawable.stat_sys_warning, );
}
}
Alarm:
You can schedule a pending intent that drives what you want when the alarm fires. The process is:
Determine how often you want the alarm to fire. You can fire at an exact time, a specific time from now (in 10 seconds..), or a specific repeat at an interval (every x seconds/minutes/etc.). You can also set a specific time to start the repeat process. The interval isn't variable. Then you have to do one shots and set another alarm for the next time. You can also set flags that determine the time format (millis, RTC, ...). Finally, you can have the alarm firing wake up the device or let it sleep and get scheduled the next time the phone is awake.
Now, as to what is scheduled. A pending intent is scheduled. The pending intent wakes up a broadcast receiver. Here's some clips of code I use to fire a timer at 1 minute past midnight daily. (It updates a widget that has to update daily.)
Intent intent = new Intent(context, DaysReceiver.class);
PendingIntent receiverIntent = PendingIntent.getBroadcast(context,
DaysConstants.UPDATE_ALARM,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Schedule the alarm!
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.cancel(receiverIntent);
if (cancelAlarm) {
MyLog.d(TAG, "setAlarm cancel");
return;
}
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
JodaTime jtime = new JodaTime();
am.set(AlarmManager.RTC_WAKEUP, jtime.afterMidnight(), receiverIntent);
//am.setRepeating(AlarmManager.RTC_WAKEUP, jtime.nowPlusMillis(30 * 1000),
// 30 * 1000, receiverIntent);
MyLog.d(TAG, "setAlarm set");
}
The JodaTime class does date and time calculations. the afterMidnight() bit above returns 1 minute after midnight tonight. The routine can be used to just cancel an outstanding alarm.
The receiver is just a normal broadcast receiver and you can do anything in it that you can do in any other broadcast receiver. (Don't forget to put the usual stuff in the manifest. Permissions, and such like.
Here's the receiver I'm using less the imports. It's pretty straight forward. It grabs all the widgets that are on home screens and updates them. The update routine is a static function in the widget provider. It's a class because it is driven from two places. The widget config and the widget provider. The timer is rescheduled every 24 hours. The alarm won't live through a boot, but the provider's on update is driven at reboot. (All that's happening is the new day calculations are performed and the widget display is updated.) You could drop my code and put in a startActivity.
Ooops. Almost forgot. Use PendingIntent.FLAG_UPDATE_CURRENT so you don't have multiple intents stacked up accidentally...
public class DaysReceiver extends BroadcastReceiver {
static String TAG = "DaysReceiver";
#Override
public void onReceive(Context context, Intent intent) {
MyLog.d(TAG, "onReceive");
updateWidgets(context);
}
private void updateWidgets(Context context) {
MyLog.d(TAG, "updateWidgets");
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName componentName = new ComponentName(context, DaysProvider.class);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(componentName);
final int N = appWidgetIds.length;
if (N < 1) {
MyLog.d(TAG, "No widgets");
return;
}
for (int i = 0; i < N; i++) {
MyLog.d(TAG, "Update widget " + Integer.toString(appWidgetIds[i]));
DaysProvider.updateAppWidget(context, appWidgetManager, appWidgetIds[i]);
}
}
}
Hope I haven't rambled to much, but I'm in a rush to get back to some other business. I don't have the time to really edit the post. Hope this helped...
Do you really need a notification? Why not fire off an activity that can do the alarm notification and disappear. You can sound an alarm, vibrate the phone, whatever. Even do a notification if you still want to...
Intent intent = new Intent(context.MyAlarmResponse);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("REASONFORALARM", "What ever you want");
context.startActivity(intent);
In the manifest, use the following theme to look like a dialog:
<activity android:name=".MyAlarmResponse"
android:theme="#android:style/Theme.Dialog">
</activity>
It doesn't have to look like a dialog. You can do a full court press with a full screen display, animation, vibrate, and sound. The user than hits your cancel key and it all goes away.