I have a CalendarView that the user can touch and save school events.
I would check every day at 15:00 PM check if in the database there are some events saved like homeworks and generate a notification of that.
What i need for do this?
AlarmManager
BroadcastReceiver (??)
Service
The AlarmManager manage the when start a Service, and in the Service i make the query that if it returns something i make the notification.
I don't know if the BroadCastReceiver is needed.
It's all or i need something else?
Can someone tell me how do that?
Activity that manage the when case:
public class MainActivity extends ActionBarActivity {
private PendingIntent pendingIntent;
private AlarmManager alarmManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set the alarm to start at approximately 2:00 p.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 16);
calendar.set(Calendar.MINUTE, 40);
Intent myIntent = new Intent(MainActivity.this, MyBroadcastReceiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent, 0);
alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
My BroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "tag");
//Acquire the lock
wl.acquire();
Log.v("ADebugTag", "It work!");
int mId = 0;
//Show the notification here.
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_action_edit)
.setContentTitle("Diario Scolastico")
.setContentText("Hai dei compiti da svolgere per domani!");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, MainActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());
//Release the lock
wl.release();
}
}
Manifest Permissions
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<receiver android:name=".MyBroadcastReceiver" />
Now i get notification but not in the established time and i don't know why!
The most appropriate use for your particular case would be the AlarmManager and a corresponding BroadcastReceiver as they were specifically created for situations like this. You don't need a service just for showing a notification.
Some problems that might lead to your issue that I saw by glancing at your code were:
alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
should be:
//It's better to use the setInexactRepeating, but this is your call
int MILLIS_IN_A_DAY = 1000 * 60 * 60 * 24; //You can use an actual calculator so you don't have to compute it every time at runtime; also, lower it to something like 10000 ms to actually check if it is working
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), MILLIS_IN_A_DAY, pendingIntent);
Then you'd want to acquire the wakelock in your BroadcastReceiver onReceive method by doing so:
#Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 'YOUR TAG');
//Acquire the lock
wl.acquire();
//You can show the notification here.
//Release the lock
wl.release();
}
Also, don't forget to register the BroadcastReceiver in your AndroidManifest.xml
Related
I want my notification to cancel it's own repeating alarm. However, I don't know how to pass pendingIntent (to cancel it later) before it is even created.
Alarms sets here:
public class Schedule extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
wakeLock.acquire();
//next is notification code. //
...
//create intent.
Intent notificationIntent = new Intent(context, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(context,
NOTIFY_ID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
...
////
wakeLock.release();
}
public void setAlarm(Context context) {
...
Intent intent = new Intent(context, Schedule.class);
intent.putExtra("DELAY", delay);
intent.putExtra("NOTIFICATION_ID", id);
intent.putExtra("TITLE_TEXT", titleText);
intent.putExtra("BIG_TEXT", bigText);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000 * 60 * delay, 1000 * 60 * delay, pendingIntent);
}
}
The key problem is that I want to cancel the repeating alarm on notification click (intent in onRecieve method), but canceling alarms requires pendingIntent, which notification is a part of. Any way to cheat the system?
Use AlarmManager.cancel() to cancel the specific alarm and use same PendingIntent that was used to create the alarm. Of course, you should use same requestCode(NOTIFY_ID) that was used before.
Try this:
Intent intent = new Intent(this, Schedule.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, NOTIFY_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
Add this code portion into your MainActivty's onCreate() method as your notification will intent to MainActivity when click on it from notification panel.
Hope this will help~
I try to set an alarm depending user chocies while setting alarm i want to send that alarm's unique notification id to reciever.java. I want to get data by this id on reciever.java.
I have a form with this form users are adding their pills and I'm saving every pill in different xml files for example pill1.xml pill2.xml. That saved pills have alarm and notification when alarm time came for example pill2.xml i will show pill2 datas in notirifacation bar.
that code on bottom is how i create alarm.
Long alertTime = new GregorianCalendar().getTimeInMillis()+10*1000;
Intent alertIntent = new Intent(ilac_hatirlatma.this, hatirlatma_detay.class);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, alertTime, PendingIntent.getBroadcast(ilac_hatirlatma.this, NOTIF_ID, alertIntent, PendingIntent.FLAG_UPDATE_CURRENT));
reciever.java
#Override
public void onReceive(Context context, Intent intent) {
createNotification(context, "İlaç Hatırlatma", "8 saatte bir içmeniz gereken 'Arvelez' adlı ilacınız bulunmaktadır.", "İlacınzı Almayı Unutmayınız!");
}
public void createNotification(Context context, String msg, String msgText, String msgAlert){
PendingIntent notificIntent = PendingIntent.getActivity(context, 0, new Intent(context, ilac_hatirlatma.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context).setSmallIcon(R.drawable.app_icon).setContentTitle(msg).setTicker(msgAlert).setContentText(msgText);
mBuilder.setContentIntent(notificIntent);
mBuilder.setDefaults(NotificationCompat.DEFAULT_SOUND);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
}
Here i prepare the alarm manager, every day at same hour
alarmManager = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getApplicationContext(), MyBroadcastReceiver.class);
pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, 0);
// Set the alarm to start at some time.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
int curHr = calendar.get(Calendar.HOUR_OF_DAY);
// Checking whether current hour is over 15
if (curHr >= 15)
{
// Since current hour is over 15, setting the date to the next day
calendar.add(Calendar.DATE, 1);
}
calendar.set(Calendar.HOUR_OF_DAY, 15);
calendar.set(Calendar.MINUTE, 30);
// every day
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
And here i have the BroadcastReceiver that generate the notification
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
//Partial_wake_lock only need CPU active
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "tag");
//Acquire the lock
wl.acquire();
int mId = 0;
//Show the notification
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_action_edit)
.setContentTitle("YOUR APP NAME")
.setContentText("TAKE THE PILLS!")
.setAutoCancel(true)
.setDefaults(-1);
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, MainActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());
//Release the lock
wl.release();
}
}
The permissions of the manifest
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
And Receiver declaration in the manifest
<receiver android:name=".MyBroadcastReceiver" />
For setting your Alarm manager read documentation
If you need to pass data between AlarmManager and BroadcastReceiver use .putExtra() like how this post explain
Hope this helps!
My app use an AlarmManager that start a BroadcastReceiver.
The BroadcastReceiver generate a reminder notification to the user.
This is the MainActivity that start the Alarm
public class MainActivity extends ActionBarActivity {
private PendingIntent pendingIntent;
private AlarmManager alarmManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set the alarm to start at approximately 2:00 p.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
int curHr = calendar.get(Calendar.HOUR_OF_DAY);
// Checking whether current hour is over 14
if (curHr >= 14)
{
// Since current hour is over 14, setting the date to the next day
calendar.add(Calendar.DATE, 1);
}
calendar.set(Calendar.HOUR_OF_DAY, 14);
// Schedule alarm manager
Intent myIntent = new Intent(MainActivity.this, MyBroadcastReceiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent, 0);
alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
And this is the BroadcastReceiver that generate the notification
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "tag");
//Acquire the lock
wl.acquire();
Log.v("ADebugTag", "It work!");
int mId = 0;
//Show the notification here.
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_action_edit)
.setContentTitle("Diario Scolastico")
.setContentText("You have homeworks for tomorrow!")
.setAutoCancel(true)
.setDefaults(-1);
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, MainActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());
//Release the lock
wl.release();
}
}
Manifest permissions:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
As you can see the alarm must start at 14 PM, but i receive the notification every time that i start the app.
There is something wrong in my code?
I use the Scheduling Repeating Alarms for setting the alarm every day at same hour, but don't work properly
The issue is you are setting the time to current day. So if you are opening your app after 14:00, your alarm manager will immediately fire.
You need to check whether the time is over 14:00 for the current day, if yes you need to change the date to the next day:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
int curHr = calendar.get(Calendar.HOUR_OF_DAY);
// Checking whether current hour is over 14
if (curHr >= 14)
{
// Since current hour is over 14, setting the date to the next day
calendar.add(Calendar.DATE, 1);
}
calendar.set(Calendar.HOUR_OF_DAY, 14);
// Schedule alarm manager
I have an app that sends a notification with AlarmManager every day at an exact time.
But it has a bug. The notification is sent whenever the app is open.
How can I get to the notification is send once a day? Thank you
MAINACTIVITY
public class MainActivity extends Activity {
private PendingIntent pendingIntent;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Calendar calendar = Calendar.getInstance();
int d = Integer.valueOf(1440);
calendar.setTimeInMillis(System.currentTimeMillis());
Intent i = new Intent(MainActivity.this, Receiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, i, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60 * d, pendingIntent);
}
}
RECEIVER
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
Intent i = new Intent(context, MainActivity.class);
Notification notification = new Notification(R.drawable.ic_launcher,"This is a test message!", System.currentTimeMillis());
long[] vibrate = {100, 100, 200, 300};
notification.vibrate = vibrate;
notification.defaults = Notification.DEFAULT_ALL;
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity(context, 0, i,PendingIntent.FLAG_UPDATE_CURRENT);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(context, "AlarmManagerDemo", "This is a test message!", pendingNotificationIntent);
notificationManager.notify(0, notification);
}
}
Code to call CallThisClass.class every int d mins
Intent myIntent = new Intent(getActivity(), CallThisClass.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
int d = Integer.valueOf(duration);
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 2);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60 * d, pendingIntent);
Code to stop calling CallThisClass.class
Intent myIntent = new Intent(getActivity(), CallThisClass.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 0, myIntent, 0);
alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
CallThisClass.class
public class CallThisClass extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
Log.i("Received", "Broadcast Received !");
// Do your stuff
}
}
Dont forget Receiver inyour AndroidManifest.xml
<receiver android:name=".CallThisClass" />
And Permission
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
You can start calling CallThisClass.class whenever you want. Eg. on a click of a button, or when your main activity start. Just make sure to Stop Calling the class when you dont want it working. Eg You want when the user first installs your application you want every 24 hours there should be something updated (notification or something), rit? in your prefrences store a variable that changes itself only if it is loaded for the first time. Check for that variable every time user enters application. if it is first time Start the Calling code. (now we dont want to call the stop code yet because we cant to keep on calling that class even if the application is closed!) close the application and it will work. And you can have a button in you setting or something for testing that when clicked will run code for not calling the class. It will stop the calling calling class every d mins i.e 24 hours in your case (also you can change the prefrnce to default value on clik of this button so that next time you start activity or click activate or something again that code to start calling that class starts). I hope it helps.
Also, i would suggest a read here for Best practices
What I am looking at doing is implementing local notifications. The idea is that dates are stored in an SQL file on the phone and when the current date reaches the date before the date in the SQL file i am looking at notifying the user with a message.
I have done a lot of research into this and have found things relating to Alarms and services. I am now really confused and have no idea which root to take. Could someone please help?
Thanks
What you want to do is use an AlarmManager for this that broadcasts a notification. You won't need to set the date in a database and manage it...just set the date in the AlarmManager. I've created a class for this which has a function for setting the time the alarm should go off, as well as receiving the broadcast then building the notification.
public class MyAlarmManager extends BroadcastReceiver {
private Context mContext;
private AlarmManager mAlarmManager;
public MyAlarmManager() {}
public MyAlarmManager(Context context) {
mContext = context;
mAlarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
}
#Override
public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "YOUR TAG");
//Acquire the lock
wl.acquire();
//You can do the processing here.
buildNotification(context);
//Release the lock
wl.release();
}
public void setReminder(long time) {
Intent intent = new Intent(mContext, MyAlarmManager.class);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, time, pi); //time is in milliseconds
}
public void buildNotification(Context context) {
long[] vibrate = { 0, 100, 200, 300 };
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("My notification")
.setContentText("Hello World!")
.setVibrate(vibrate)
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, YourLaunchActivity.class);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(ConferencesActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
int randomId = 1000303;
mNotificationManager.notify(randomId, mBuilder.build());
}
}
Then be sure to add this in your manifest and use whatever your app package name is:
<receiver android:name="com.example.myapp.MyAlarmManager"></receiver>
Hope that helps!