How to display an alert box using Alarm Manager and BroadcastReceiver - android

I want my android app to pop-up an alert dialog box at specific time of each day. Of what I have understood is that we need to use Alarm manager to set the time of the day on repeating, and then send a broadcast to display the alert dialog box. The alert box should be displayed at the specified time even if the app is closed. I have tried the following code but it does not do anything at the specified time. Please suggest what needs to be done. I am new to android development and this is my very first implementation.
Main_Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR,Calendar.MONTH,Calendar.DAY_OF_MONTH,6, 10);
setAlarm(calendar.getTimeInMillis());
}
private void setAlarm(long timeInMillis) {
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlertBox.class);
PendingIntent penIntent = PendingIntent.getBroadcast(this,0,intent,0);
am.setRepeating(AlarmManager.RTC_WAKEUP,timeInMillis,AlarmManager.INTERVAL_DAY,penIntent);
//Toast.makeText(this,"Alarm is set",Toast.LENGTH_SHORT).show();
}
AlertBox
#Override
public void onReceive(Context context, Intent intent) {
DisplayAlertBox(context, "Tip of the Day");
}
private void DisplayAlertBox(Context context, String msg) {
Toast.makeText(context, "Dialog Box should display Now", Toast.LENGTH_LONG).show();
PendingIntent alertBox = PendingIntent.getActivity(context,0, new Intent(context,MainActivity.class),0);
AlertDialog.Builder aBuilder = new AlertDialog.Builder(context);
aBuilder.setTitle("Message");
aBuilder.setMessage(msg);
aBuilder.setPositiveButton("Accept",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int whichButton)
{
}});
aBuilder.create();
aBuilder.show();
}

The reason why nothing is happening is because you don't have a clear understanding of BroadcastReceiver.
BroadcastReceivers, once registered, will sit there waiting for a broadcast that it can receive. Registering a BroadcastReceiver can be done in both your Manifest file or through your code. The broadcast that it can wait to receive can be either an implicit or explicit broadcast. But in your case, it's an explicit broadcast. So you would declare it in your Manifest like so:
<receiver android:name="com.package.AlertBox">
<intent-filter>
<action android:name="can.be.any.name.like.tip.of.the.day"
</intent-filter>
</receiver>
You may also register the BroadcastReceiver through code if you don't want to do so through the Manifest.
Your problem is that the intent that you're sending to your AlarmManager is Intent intent = new Intent(this, AlertBox.class). What this does is that it's only going to start your BroadcastReceiver, which isn't necessary once it's already registered. It's onReceive() is never called this way.
Your AlertBox will only show the AlertDialog when onReceive() is called, but onReceive is never called because a BroadcastReceiver's onReceive is only called when it receives the broadcast it's registered to receive.
So your setAlarm() method should be written like this:
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent("can.be.any.name.like.tip.of.the.day");
PendingIntent penIntent = PendingIntent.getBroadcast(this,0,intent,0);
am.setRepeating(AlarmManager.RTC_WAKEUP, timeInMillis, AlarmManager.INTERVAL_DAY, penIntent);
Keep in mind that the String that's used as the action of the Intent must match the String that your Broadcast Receiver is listening to. This way, the onReceive() method will be able to trigger.
However, I should also mention that the BroadcastReceiver should not be where you run your AlertDialog. BroadcastReceivers are meant for short execution of codes and are not meant to persist for a lengthy amount of time. For that, an Activity or Service would be a better option.
You should consider having the AlarmManager launch a transparent Activity that hosts a DialogFragment instead.

Related

AlarmClock intent says "No apps can perform this action."

I am trying to set an alarm in the alarm clock with an intent. I am using an Android One Phone (which has the unmodified OS) and have the Clock app installed (which came pre-installed) which allows setting alarm. Setting an alarm has worked in the past when I had used an AlarmManager and PendingIntent when I had to set the alarm in the background. That shows that my Clock app can respond to AlarmClock intents. But now when I am trying to send an intent from the foreground of my app, it says:
No apps can perform this action.
This is not from the stack trace, but a popup which is shown to users to choose which Clock app to choose to set the alarm (or which app to use in general for an intent)
Here's the Activity's onCreate() code where I am calling it:
public class MainActivity extends AppCompatActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
...
Utils.setAlarm(this, Utils.getLDT(epochTime).plusHours(8));
}
}
Here's the Utils#setAlarm function that sends the intent:
public class Utils {
public static void setAlarm(Context context, LocalDateTime alarmTimeDT) {
Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM);
intent.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
intent.putExtra(AlarmClock.EXTRA_HOUR, alarmTimeDT.getHour());
intent.putExtra(AlarmClock.EXTRA_MINUTES, alarmTimeDT.getMinute());
intent.putExtra(AlarmClock.EXTRA_MESSAGE, "Good Morning");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
...
}
This is the additional code that was used in the past for the same device and same Clock app. This is for cancelling an already set alarm, but the code used to set the old alarm was similar except for the cancelling part:
//cancel old alarm
AlarmManager alarmMgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
PendingIntent alarmIntent = PendingIntent.getActivity(
this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
if (alarmIntent != null) {
alarmMgr.cancel(alarmIntent);
} else {
Log.i(TAG, "intent is null");
}
What am I doing wrong? Any help appreciated.
The below comments is just questioning and asking for more clarification on the question, which were done as asked for. So you may skip reading them
No apps can perform this action.
This happens when you don't have the required permission to set the alarm.
From AlarmClock reference:
Applications that wish to receive the ACTION_SET_ALARM and ACTION_SET_TIMER Intents should create an activity to handle the Intent that requires the permission com.android.alarm.permission.SET_ALARM.
Request the SET_ALARM permission:
<mainfest
...
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
</manifest>

AlarmManager alarm start when system time is changed by user?

i am using AlarmManager class for setting Alarms it is working fine.
But if i set alarm like 9pm and current time is 8pm and i changed the system time to 10pm
then alarm 9pm alarm start automatically. so to solve this issue
i have searched so much but did not found any good answer
Please help
here is my code for alarm setting
final int id = (int) System.currentTimeMillis();
Intent intent = new Intent(this, AlarmReceiver.class);
intent.putExtra("requestCode", id);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 2*60*1000, pendingIntent);
One of the options is to store all set alarms in database, then create a BroadcastReceiver which will listen for ACTION_TIME_CHANGE action. When user changes time it will be triggered. Then create a IntentService which will be responsible for resetting alarms. In this service class:
Read db and identify all passed alarms.
Cancel passed alarms
Set alarms for next day
Your code may look like as below:
In your Manifest:
<uses-permission android:name="android.permission.ACTION_TIME_CHANGE"/>
and below activities:
<receiver android:name=".TimeChangedReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.TIME_SET" />
</intent-filter>
</receiver>
<service android:name=".RestartAlarmsService"/>
Create class "TimeChangedReceiver" inside of which:
public class TimeChangedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if("android.intent.action.TIME_SET".equals(intent.getAction())) {
Intent i = new Intent(context, RestartAlarmsService.class);
ComponentName service = context.startService(i);
}
}
}
Create "RestartAlarmsService" class inside of which:
public class RestartAlarmsService extends IntentService {
public RestartAlarmsService() {
super("RestartAlarmsService");
}
#Override
protected void onHandleIntent(Intent intent) {
// read db here
// then cancel passed alarms
// reset them to next day
}
}
You can find many tutorials on how to use Databases and implement it in your code. Hope my answer is somehow helpful.
yes it will give you broadcast, as your pending intent object is still attached to that event while you change time that is greater than you alarm firing time.
solution- validate your condition while you receive broadcast from alarm manager

android activity comes to foreground after alarm manager

I have application, which makes event in alarm manager, and at specific time its called.
Code looks like this
Intent intent = new Intent(this, AlarmActivity.class);
pendingIntent = PendingIntent.getActivity(this,req_code, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),AlarmManager.INTERVAL_DAY*7,
pendingIntent);
Intent calls this activity.
public class AlarmActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void onStart(){
super.onStart();
//Change ringer mode
//Add notification in status bar
//Other booring stuff here...
Toast.makeText(this,"Finishing",2000).show();
finish();
}
}
in booring stuffthere are is code which should run in background (change ringermode)
Everything works for me, except one thing. Whenever the alarm manager calls my activity - the application comes to foreground.
When it only should change ringer mode in background, and add notification in status bar.
Any way to not allow application come to foreground?
You should do all of this in a BroadCastReceiver. There is no UI, and there is a Context variable passed on to the Receiver's onReceive() method which allows you to basically do anything the Activity does, without having an actual UI. This means that you can set the ringer, show the status bar notification, etc.
Your BroadcastReceiver class should look something like:
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Change ringer mode
//Add notification in status bar
//Other boring stuff here...
Toast.makeText(context,"Finishing",2000).show();
}
}
Note that for your Toast, the variable named context is used.
And your AlarmManager code should look something like this:
Intent intent = new Intent(this, AlarmBroadcastReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this,req_code, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),AlarmManager.INTERVAL_DAY*7,
pendingIntent);
Your manifest should have this:
<receiver android:name=".AlarmBroadcastReceiver" >
</receiver>
Add this line to the Activity in your AndroidManifest
android:theme="#android:style/Theme.NoDisplay"
and you have an Activity with nothing to display. Since you are already calling finish(); in your code, it will look like it is running in background.

Android: AlarmManager on firing correct alarms

ALREADY ANSWERED, FOR THOSE WHO HAVE THE SAME PROBLEM PLEASE REFERE TO THE BOTTOM OF THIS POST
I have this part on my app which schedules an alarm, all was working well, it scheduled the alarm correctly but there is a erratic behavior wherein sometimes, when the alarm scheduled is fired, instead of firing once, it fired several times, i know this cuz everytime an alarm fires i displayed "ALARM FIRED" on logcat, there are several ALARM FIRED on my logcat, sometimes up to 10, what im confused about is that i only scheudled that alarm once, and it fired many times. Here is Codes:
THIS IS FOR SCHEDULING MY ALARM THIS IS ON THE Helper class accessed in static way
public final static String ACTION = "com.medical.organizer.utilities.NotifyReciever";
private static NotifyReciever RECIEVER = new NotifyReciever();
public static void scheduleAlarm(Context context,String message,int rCode, long triggerTime)
{
RECIEVER = new NotifyReciever();
NotifyAlarm.TRIGGER_TIME = triggerTime;
NotifyAlarm.CONTEXT = context;
IntentFilter inFil = new IntentFilter(ACTION);
NotifyAlarm.CONTEXT.registerReceiver(RECIEVER, inFil);
Intent intent = new Intent(ACTION);
intent.putExtra("message", message);
NotifyAlarm.INTENT = intent;
NotifyAlarm.startAlarm(rCode);
}
public static void cancelAlarm(Context context, int requestCode)
{
RECIEVER = new NotifyReciever();
NotifyAlarm.CONTEXT = context;
IntentFilter inFil = new IntentFilter(ACTION);
NotifyAlarm.CONTEXT.registerReceiver(RECIEVER, inFil);
Intent intent = new Intent(ACTION);
NotifyAlarm.INTENT = intent;
//context.unregisterReceiver(RECIEVER);
NotifyAlarm.stopAlarm(requestCode);
}
THIS IS FOR THE ALARM ITSELF
public class NotifyAlarm {
public static Context CONTEXT;
public static Intent INTENT;
public static long TRIGGER_TIME;
public static void startAlarm(int requestCode)
{
AlarmManager am = (AlarmManager) CONTEXT.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(CONTEXT, requestCode, INTENT, 0);
am.set(AlarmManager.RTC_WAKEUP, TRIGGER_TIME, pendingIntent);
Log.d("AlarmCheck", "Alarm Started for the First Time, set() was called");
}
public static void stopAlarm(int requestCode)
{
AlarmManager am = (AlarmManager) CONTEXT.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(CONTEXT, requestCode, INTENT, 0);
am.cancel(pendingIntent);
Log.d("ALARMSTOP","========ALARM WAS STOPPED AT THIS POINT==========");
}
}
THIS IS FOR MY ALARM RECIEVER (BROADCAST RECIEVER)
public class NotifyReciever extends BroadcastReceiver {
private Context context;
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
Log.d("AlarmCheck","ALARM FIRED!");
AlertDialog.Builder build = new AlertDialog.Builder(context);
String message = intent.getStringExtra("message");
build.setMessage(message);
build.setCancelable(false);
build.setPositiveButton("Snooze", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//Rechedules the alarm after 25 secs time of interval is for
//testing purposes only
NotifyReciever.this.context.unregisterReceiver(NotifyReciever.this);
Helper.scheduleAlarm(NotifyReciever.this.context, s,
s.getRequestCode(),System.currentTimeMillis()+Helper.TWENTY_FIVE_SEC);
}
});
build.setNegativeButton("Dismiss", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//CANCELS THE ALARM
Helper.cancelAlarm(NotifyReciever.this.context, s.getRequestCode());
}
});
AlertDialog alert = build.create();
alert.show();
}
}
Note that the receivers aren't declared through XML, they are registered programatically so to support dialogs.
Consider this situation, this is where i notice that behavior always occurs, Say, i've added a schedule and scheduled the alarm # 5:00am (Current time is 4:59), so at first it fired completely fine, then i decided to rescheduled that alarm to 5:01 (Current time 5:00) then this occurs, the alarm is fired for several times. the alear dialog appears several times, have to fast click them all to cancel the dialogs, sometimes my app crashes due to too many dialogs showing up.
anyone knows how to go about this problem please do share and anybody knows how to properly schedule and fire an alarm please do share, as well as scheduling and firing multiple alarms as well as canceling them would be much appreciated. Explanation and some examples would be better.
EDIT
Legend: a colored dot on the side means that it is fired a at specific time and that was what logged on logcat, say an alarm fired # 4:00 display the one with several blue dots
EDIT THIS IS THE ANSWER
So this is what i've discovered , mine is that you have to register your reciever only once, so to avoid multiple returns from the intentFilter, which matches all intents using ur ACTION, in my case i've registered my reciever over and over again so there are already many instances of intents with the same ACTIOn thus returning multiple recievers and yeah firing multiple alarms at a specified time instead of firing only one receiver, so yeah REGISTER OONLY ONCE YOUR RECEIVER MAYBE AT A GLOBAL CLASS IF YOU DECIDE NOT TO DECLARE YOUR RECEIVER IN XML

Android-Broadcast Receiver

I am new to android. I what to know the difference between Intent and BroadcastReceiver. I am more confused with BroadcastReceiver than Intent.
Please help me out. Simple code will be helpful.
Ok, I will explain it with an example.
Let's suppose I want to create an app to check subway status from it's webpage. I also want a system notification if the subway is not working ok.
I will have:
An Activity to show results.
A Service to check if the subway is working and show a notification if it's not working.
A Broadcast Receiver called Alarm Receiver to call the service every 15 minutes.
Let me show you some code:
/* AlarmReceiver.java */
public class AlarmReceiver extends BroadcastReceiver {
public static final String ACTION_REFRESH_SUBWAY_ALARM =
"com.x.ACTION_REFRESH_SUBWAY_ALARM";
#Override
public void onReceive(Context context, Intent intent) {
Intent startIntent = new Intent(context, StatusService.class);
context.startService(startIntent);
}
}
Explanation:
As you can see you can set an alarm. and when the alarm is received we use an intent to start the service. Basically the intent is a msg which can have actions, an serialized stuff.
public class StatusService extends Service {
#Override
public void onCreate() {
super.onCreate();
mAlarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intentToFire = new Intent(AlarmReceiver.ACTION_REFRESH_ALARM);
mAlarmIntent = PendingIntent.getBroadcast(this, 0, intentToFire, 0);
}
#Override
public void onStart(Intent intent, int arg1) {
super.onStart(intent, arg1);
Log.d(TAG, "SERVICE STARTED");
setAlarm();
Log.d(TAG, "Performing update!");
new SubwayAsyncTask().execute();
stopSelf();
}
private void setAlarm() {
int alarmType = AlarmManager.ELAPSED_REALTIME_WAKEUP;
mAlarms.setInexactRepeating(alarmType, SystemClock.elapsedRealtime() + timeToRefresh(),
AlarmManager.INTERVAL_HALF_DAY, mAlarmIntent);
}
}
Explanation:
The service starts and:
Set the alarm for the next call. (Check the intent it's used. Just a msg)
Calls an AsyncTask which takes care of updating an notifying the Activity
It doesn't make sense to paste the AsyncTask but when it finished it calls:
private void sendSubwayUpdates(LinkedList<Subway> subways) {
Intent intent = new Intent(NEW_SUBWAYS_STATUS);
intent.putExtra("subways", subways);
sendBroadcast(intent);
}
This creates a new Intent with a certain NEW_SUBWAYS_STATUS action, put inside the intent the subways and sendBroadcast. If someone is interested in getting that info, it will have a receiver.
I hope I made myself clear.
PS: Some days ago someone explained broadcast and intents in a very cool way.
Someone wants to share his beer, so he sends a broadcast
with an intent having action:"FREE_BEER" and with an extra: "A glass of beer".
The API states:
A BroadcastReceiver is a base class for code that will receive intents sent by sendBroadcast().
An intent is an abstract description of an operation to be performed.
So, a BroadcastReceiver is just an Activity that responds to Intents. You can send your own broadcasts or even the Android Device can send these system wide broadcasts including things like the battery is low, or the device just booted-up.

Categories

Resources