I have used a timer method in an Activity class. In that method I have an intent from Activity class to a BroadcastReceiver class.
This BroadcastReceiver class will call on every 15 minutes at background by using AlarmManager.
When I call the BroadcastReceiver class I would like to raise an AlertDialog.
public void timerMethod(){
Intent intent = new Intent(Activity.this,
BroadcastReceiverClass.class
);
PendingIntent sender = PendingIntent.getBroadcast(
QualityCallActivity.this,0, intent, 0
);
// We want the alarm to go off 30 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, 60*1000, sender);
}
BroadcastReceiverClass.java
public void onReceive(Context context, Intent intent)
{
dialogMethod();
}
How can I raise an AlertDialog from BroadcastReceiver class from a background process?
If your activity is running when the BroadcastReceiver gets the intent you should be able to use runOnUiThread to run a method that creates an AlertDialog, e.g.:
public void onReceive(Context context, Intent intent)
{
runOnUiThread(new Runnable() {
public void run() {
AlertDialog.Builder d = new AlertDialog.Builder(MyActivity.this);
b.setMessage("This is a dialog from within a BroadcastReceiver");
b.create().show();
}
});
}
This works if you make your BroadcastReceiver an inner class to your Activity.
In short: It is not possible.
Only Activity's can create/show dialogs. In fact, this has been asked more then once:
AlertDialog in BroadcastReceiver
How can I display a dialog from an Android broadcast receiver?
Also, this would give a very bad user-experience:
If the user is not in your application (let's say he's playing a
Game) and your Dialog pops up every 15 minutes, this will be very
annoying for him.
If the user is in your application, there are several other (better
suited) ways to notify him that something has been executed.
Better suited ways
In fact, you can create/show a Toast from an BroadcastReceiver. This Toast will also bee shown when the user is not "in your application".
Also, you can send a Notification (shown in the Notification-Bar at the top of your screen) from a BroadcastReceiver. A tutorial on how to do this (it does not differ from how you do it in an Activity, except that you use the passed Context-Object from the onReceive-method).
The Notification will also be shown when the user is not "in your application" and is IMO the best solution to this problem.
1) In Activity:
public static Context ctx;
onCreate {
ctx = this;
}
public void showAlertDialog(Context context, String title, String message) {
final AlertDialog alertDialog = new AlertDialog.Builder(context).create();
// Setting Dialog Title
alertDialog.setTitle(title);
// Setting Dialog Message
alertDialog.setMessage(message);
// Setting OK Button
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Okay",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which)
{
alertDialog.dismiss();
}
});
// Showing Alert Message
alertDialog.show();
}
2) In BroadcastReceiver.onReceive:
YourActivity ac= new YourActivity ();
ac.showAlertDialog(YourActivity.ctx, "test", "test");
Related
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.
I have a dialog activity which sets up an alert dialog every time the alarm goes off. Now this alert dialog can be infront of any activity. As it gets called by the alarm manager when the alarm is supposed to go off.
The problem is that if this alert dialog comes infront of the main activity which holds the list of upcoming alarms then when I "dismiss" the alarm, that alarm should get removed from the list( which does get deleted) but after the alert dialog disappears the main activity doesn't get updated unless I resume the activity or go to next activity and then back to main activity.
I tried calling the main activity inside the onDismiss method of the dialog like this:
alert.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
((MainActivity) context).customAdapter.notifyDataSetChanged();
}
});
However I get an exception that my DialogActivity's context can't get converted into main activity's context. How can I solve this?
Here's my Dialog Activity class
public class DialogActivity extends AppCompatActivity {
AlarmManager alarmManager;
PendingIntent pendingIntent;
Intent startSetAlarm;
Intent i;
Intent intent;
String alarmStatus;
int alarmID;
String alarmName;
String alarmTime;
String alarmAMPM;
String alarmSound;
String snoozingType;
Context context;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private ShakeListener mShakeDetector;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dialog);
........
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder
.setTitle("Alarm Clock")
.setMessage("What to do with " + alarmName + ": " + alarmTime + " " + alarmAMPM +"?")
.setCancelable(false)
.setPositiveButton("Dismiss", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
alarmManager.cancel(pendingIntent);
i.putExtra("Status","Alarm Off");
i.putExtra("calledBefore",true);
i.putExtra("Alarm ID", alarmID);
i.putExtra("Alarm Name", alarmName);
i.putExtra("Alarm Time", alarmTime);
i.putExtra("Alarm AMPM", alarmAMPM);
i.putExtra("Alarm Sound", alarmSound);
i.putExtra("Snooze Type", snoozingType);
sendBroadcast(i);
dialog.dismiss();
finish();
//startActivity(startSetAlarm);
}
})
.setNegativeButton("Snooze", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id)
{
alarmManager.cancel(pendingIntent);
i.putExtra("Status","Alarm Off");
i.putExtra("calledBefore",true);
i.putExtra("Alarm ID", alarmID);
i.putExtra("Alarm Name", alarmName);
i.putExtra("Alarm Time", alarmTime);
i.putExtra("Alarm AMPM", alarmAMPM);
i.putExtra("Alarm Sound", alarmSound);
i.putExtra("Snooze Type", snoozingType);
sendBroadcast(i);
Snooze();
dialog.dismiss();
finish();
}
});
final AlertDialog alert = builder.create();
alert.show();
And then I call the onDismiss method which I showed earlier. I also tried making a constructor of DialogActivity and initializing dialogactivity's object in main, to pass main's context into it however I get the error that "Dialog activity doesn't have a constructor with no parameters" If I make a default constructor, I still get an exception and it doesn't work.
UPDATE
I figured it out. I had to retrieve my list stored in shared preferences in order to get the updated one. The updated list was only getting called in onCreate not in onResume.
However I have another problem now. Which is still related to the same activity life cycle dilemma. If my application is closed (and is not in opened apps list) and I receive the dialog notification, If I dismiss the alarm, it turns off and the dialog goes away. However I can see my app now in the recent list. And when I open my app from there, my dialog activity is active and it just keeps on showing the dialog and doesn't let me enter the app. Unless I go to the app drawer and open the app from there. Here is a screenshot of what I mean.
Dialog Problem
You must use BroadcastReceiver or EventBus library . Your activity before create not to be refresh you ListView .
So my app has a timer that displays in the main activity as it is counting down. I want an alarm to play when the timer is done, so I schedule an intent that sounds the alarm using AlarmManager and a class to extend BroadcastReceiver.
Everything works fine until the alarm goes off. I traced the crash to the line where I call show() on my AlertDialog. I feel like it has something to do with the application context and the code not being in MainActivity or something, but I can't seem to find anything with a similar configuration and the same crash source.
Here is the alert dialog code
public class SoundAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
...///Play sound code is here and works
final CharSequence [] options = {"OK"};
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Title");
builder.setMessage("Beer is done!");
builder.setCancelable(false);
builder.setItems(options, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
if(which == 0) {
mp.stop();
mp.release();
}
}
});
AlertDialog alert = builder.create();
alert.show();
... //other stuff
Here is the code that schedules with the AlarmManager which is found in MainActivity.java:
//Schedule the alarm
Intent alarmIntent = new Intent(MainActivity.this, SoundAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
Calendar fireTime = Calendar.getInstance();
fireTime.setTimeInMillis(System.currentTimeMillis());
fireTime.add(Calendar.MILLISECOND, time);
alarmManager.set(AlarmManager.RTC_WAKEUP, fireTime.getTimeInMillis(), pendingIntent);
Also, as an aside, changing the MainActivity.this to getApplicationContext() for the pending intent does not fix the crash. Saw a lot of people suggesting using one or the other, but my crash persists no matter which one I use.
I feel like it has something to do with the application context and the code not being in MainActivity or something,
Yes, you need an Activity to show a Dialog.
What you can do is build a separate Activity with the layout you want and start it from the Receiver. You can add the following code to the <activity> tag of your manifest.xml to make it appear as a Dialog.
android:theme="#android:style/Theme.Dialog"
From the Docs
Note: Activities provide a facility to manage the creation, saving and restoring of dialogs.
This question already has answers here:
How to stop displaying message from Toast when Application is closed?
(5 answers)
Closed 9 years ago.
Assume that you have a Button that whenever you click on it, it displays a Toast with the message "Hello".
If you decide to click on that Button 20 times repeatedly, the Toasts will be displayed asynchronously, waiting each one its turn. However, this is not what I really want.
What I want is the following:
Whenever I press the Button, I want it to cancel the previous displayed Toast and display the actual one. So that when I close the app, no Toasts will be displayed if ever the user decides to mess with the app by clicking on the Button 100 times within a very small period.
You'll need to declare your Toast at a class level, and then call toast.cancel() before constructing a new Toast object and showing it.
public class XYZ extends Activity {
Toast mToast;
public void onCreate(Bundle b) {
.....
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if(mToast != null)
mToast.cancel();
mToast = Toast.makeText.....;
}
});
}
}
Here' another solution. If all you want is to prevent multiple toasts from being displayed for fast clicks then a combination of AlarmManager and a PendingIntent should work too. Now bear in mind, I haven't tested this and haven't checked if it compiles.
AlarmManager mAlarm;
PendingIntent mPendingIntent;
//toast delay for a second
int toastDelay = 1000;
#Override
public void onCreate (Bundle savedInstanceState) {
Intent i = new Intent(context, MySimpleBroadcastReceiver.class);
//optionally set an action
i.setAction("show:toast");
mPendingIntent = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
mAlarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
public void onClick(View v) {
//set the alarm to trigger 1 second from current time
mAlarm.set(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis() + toastDelay), mPendingIntent);
}
#Override
protected void onDestroy () {
if (mAlarm != null) {
mAlarm.cancel(mPendingIntent);
}
mAlarm = null;
mPendingIntent = null;
}
Create the broadcast receiver and remember to add it to your AndroidManifest.xml:
public class MySimpleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive (Context context, Intent intent) {
//optionally check the action that triggered the broadcast..useful if you want to use this broadcast for other actions
if (intent.getAction().equals("show:toast")) {
Toast.makeText(context, "Hello", Toast.LENGTH_SHORT).show();
}
}
}
You can read about PendingIntent.FLAG_CANCEL_CURRENT.
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