I've searched for a solution to this problem but have been unable to find one.
The problem I have is that an alarm is sounded OK, however the MainActivity has closed and is not re-displayed .
How can I re-display the MainActivity in the following code:
public class AlarmReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
//this will update the UI with message
AlarmActivity inst = AlarmActivity.instance();
inst.setAlarmText("Alarm! Wake up! Wake up!");
//this will sound the alarm tone
//this will sound the alarm once, if you wish to
//raise alarm in loop continuously then use MediaPlayer and setLooping(true)
Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
if (alarmUri == null) {
alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
}
Ringtone ringtone = RingtoneManager.getRingtone(context, alarmUri);
ringtone.play();
//this will send a notification message
ComponentName comp = new ComponentName(context.getPackageName(),
AlarmService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
The code is code that I downloaded as an example to work with from JavaPapers
http://javapapers.com/android/android-alarm-clock-tutorial/
my suggestion
send a broadcast and have the reciever / or service start the activity for you
I did attempt to use a broadcast, however it did not work, so likely what I did was incomplete.
While the following code did work (last 3 lines were added), it seems to me that it is wrong because I presume it creates a new instance of MainActivity. The MainActivity is AlarmActivity in the original version.
The code that "works" in AlarmService.java is as follows:
private void sendNotification(String msg) {
Log.d("AlarmService", "Preparing to send notification...: " + msg);
alarmNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent mPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
NotificationCompat.Builder alarmNotificationBuilder = new NotificationCompat.Builder(
this).setContentTitle("Alarm").setSmallIcon(R.mipmap.ic_launcher)
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg);
alarmNotificationBuilder.setContentIntent(mPendingIntent);
alarmNotificationManager.notify(1, alarmNotificationBuilder.build());
Log.d("AlarmService", "Notification sent.");
Intent mIntentMain = new Intent(this, MainActivity.class);
mIntentMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
this.startActivity(mIntentMain);
}
The relevant code that I added is the last 3 lines. I put this into AlarmService.java because it extends IntentService. The original code posted in first posting (above) is from AlarmReceiver.java which extends WakefulBroadcastReceiver. I presume that what I should be doing is to cause the existing MainActivity to display rather than creating another.
Edited: 29-Sep-2016
Because the Main Activity may already be displayed, what I finally did to handle this was as follows:
if (fn_IsMainActivityDisplayed(this) == false) {
System.out.println("Main activity is not running. Now recreating");
try {
PendingIntent mPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), PendingIntent.FLAG_ONE_SHOT);
mPendingIntent.send(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
} catch (Exception jExc) {
System.out.println("AlarmService: PendingIntent failed: Error = " + jExc.getMessage());
}
}
The code to determine if Main Activity is displayed was found on SO. I'm unsure if this is 100% correct, but it appears to work OK.
Related
I started working with Notifications and to improve user expirirence I added button to notification "MARK AS READ", so when it is pressed - message will hide;
I had a few problems, in database each message has "read" field which is boolean, in method onDataChange() I loop and check if any of messages have this field as false if they have I call makeNotification(), looks fine, where is problem??? - e.x. I have 2 notifications, I cancel one(the app goes to database and change field to true, so now onDataChange() will be called), but another isn't cancelled and because onDataChange() was called now I have same notification appeared twice.....
I tried to fix this by building array of messages that are read and already displayed, not the best solution I think, but even previous problem was somehow solved this is a wierd one.
When notitifcation appears in notification list it has button "MARK AS READ", when I press it notififcation hides, but only if I start from the highest to the lower ones, so if I press second notification first foldes, if I press third first folds..
In onCreate() counter is set to 1;
public void makeNotification()
{
Intent activityIntent = new Intent(this, Notifications.class);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, activityIntent, 0);
Intent broadcastIntent = new Intent(getApplicationContext(), NotifUpdater.class);
broadcastIntent.putExtra("seconds", message.getSeconds());
broadcastIntent.putExtra("id", String.valueOf(counter));
PendingIntent actionIntent = PendingIntent.getBroadcast(this, 0,
broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, App.CHANNEL_ID)
.setVibrate(new long[]{100, 0, 100})
.setSmallIcon(R.drawable.ic_shield)
.setContentTitle(message.getTime() + " | " + message.getClient())
.setContentText(message.getMessage())
.setContentIntent(contentIntent)
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.addAction(0, "MARK AS READ", actionIntent)
.build();
notificationManager.notify(counter, notification);
counter += 1;
}
// Broadcast which is triggered by pressing button
public class NotifUpdater extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
FirebaseDatabase database = FirebaseDatabase.getInstance();
String seconds = intent.getStringExtra("seconds");
int id = Integer.parseInt(intent.getStringExtra("id"));
database.getReference("latest").child(seconds).child("read").setValue(true);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
notificationManager.cancel(id);
}
}
You should have : FLAG_CANCEL_CURRENT
like :
PendingIntent actionIntent = PendingIntent.getBroadcast(this, NOTIFICATION_ID, buttonIntent, PendingIntent.FLAG_CANCEL_CURRENT);
not FLAG_UPDATE_CURRENT
Regarding your first issue, I'd just set an indicator for each notification, "wasShown" or something of the sort that is only set to true once you have showed the notification and when ever you are iterating your notifications, only show those who has "wasShown" set to false.
Regarding your 2nd problem, I'm not familiar with FirebaseDatabase but it sounds like its an ID problem. Did you make sure the ID you are getting from the intent is the right one?
I'm making an app to remind the user of something. I want to show a notification at some time in the future. I've written the code below, following some tutorials, but it doesn't seem to work. At the time I expect the notification, it doesn't show up.
I'm using a BroadcastReceiver and the AlarmManager to make a notification at the desired time. Here's my (simplified) code.
Code to set the time:
try {
Date date = format.parse(timeInput);//This part works
long time = date.getTime();//Get the time in milliseconds
Intent i = new Intent(getBaseContext(), AlarmReceiver.class);
PendingIntent alarmSender = PendingIntent.getBroadcast(getBaseContext(), 0, i, 0);
AlarmManager am = (AlarmManager) getBaseContext().getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, time, alarmSender);
Toast.makeText(getBaseContext(), "Keep the app running to receive a reminder notification", Toast.LENGTH_LONG).show();
super.onBackPressed();
}catch(Exception e){
Toast.makeText(getBaseContext(), "Parsing error. Format:\ndd/MM/yyyy and HH:mm", Toast.LENGTH_SHORT).show();
}
The AlarmReceiver.onReceive() method:
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MenuActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, i, 0);
NotificationCompat.Builder nBulder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.notify_icon)
.setContentTitle("title")
.setContentText("text")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat nManager = NotificationManagerCompat.from(context);
nManager.notify(0, nBulder.build());
}
Everything is properly declared in the manifest file.
<receiver
android:name=".AlarmReceiver"
android:enabled="true"
android:exported="true"></receiver>
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
throw new UnsupportedOperationException("Not yet implemented");
}
}
Minor Changes:
try {
long time = System.currentTimeMillis();
Intent i = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent alarmSender = PendingIntent.getBroadcast(getApplicationContext(), 0, i, 0);
AlarmManager am = (AlarmManager) getApplication().getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, time, alarmSender);
} catch(Exception e){
Toast.makeText(getBaseContext(), "Parsing error. Format:\ndd/MM/yyyy and HH:mm", Toast.LENGTH_SHORT).show();
}
Difference between getContext() , getApplicationContext() , getBaseContext() and "this"
I've found another way to do it. Instead of using a BroadcastListener and the AlarmManager, I'm using a new Thread. It waits until System.currentTimeMillis() == time and runs a runnable on the UI thread using runOnUIThread(). In that runnable, a notification is made.
I don't know if this is a good/efficient solution, but it does the job fine.
I want a method to be executed when I press a button on my notification. For that purpose I am adding an action with a PendingIntent to my notification:
Intent intent = new Intent(context, AlertActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
Notification notification = new Notification.Builder(MainActivity.this)
.setContentTitle("New Notification")
.setContentText("Click Here")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.addAction(R.mipmap.ic_launcher, "Test2", pendingIntent)
.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(0, notification);
That works, however I don't want to start an Activity when the user invokes the action. I just need to do some work.
For that purpose I implemented a Service which should be targeted by the PendingIntent instead:
public class MyServices extends IntentService {
public MyServices() {
super("MyServices");
}
#Override
protected void onHandleIntent(Intent intent) {
clearNotification();
}
public void clearNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.cancel(0);
Intent intent = new Intent(MyServices.this, MainActivity.class);
//Starting new activity just to check
startActivity(intent);
}
}
I create the PendingIntent like this:
final Intent intent = new Intent(context, MyServices.class);
final PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
However when I invoke the action on my notification nothing happens. What am I doing wrong?
A Notification is not part of your application. It is managed by the OS. It just so happens that there are APIs you can use to show/cancel/etc notifications.
A pending intent allows for external code (Notifications for example) to launch your app/activity/service/broadcastreceiver. This cannot be done without a pending intent.
What my task is to execute some piece of code when a specific action button is clicked, and clear notification; without starting any activity
You don't have to start an activity. You can do it in a broadcastreceiver that has no UI. Or, as CommonsWare suggested, use an IntentService, depending on what what you are doing in your "piece of code". IntentServices handle work in a separate thread.
I'm trying to detect when one of my notifications is cleared (either by swiping it away individually, or through the "delete all" notifications button). I'm trying to dismiss an AlarmManager alarm, but so far, it hasn't been working for me. What's wrong with my code?
onCreate(Bundle savedInstanceState) {
...
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.flag_red_large, reminderName, System.currentTimeMillis());
notif.deleteIntent = PendingIntent.getService(this, notifID, new Intent(this, CleanUpIntent.class), 0);
//Destroy the activity/notification.
finish();
}
class CleanUpIntent extends IntentService {
public CleanUpIntent() {
super("CleanUpIntent");
}
#Override
protected void onHandleIntent(Intent arg0) {
System.out.println(">>>>>>>>>>>>>>>>>>>" + "Repeating Alarm Cancelled...");
Intent i = new Intent("com.utilityapps.YouForgotWhat.DisplayReminderNotification");
int reminderID = i.getExtras().getInt("reminderID");
PendingIntent displayIntent = PendingIntent.getBroadcast(this, reminderID, i, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(displayIntent);
displayIntent.cancel();
}
}
}
As you can see, I threw in a System.out.println() into my sub-class to check to see if my code is even reaching that class. I can't see that line in my LogCat output, so I'm assuming that for some reason, my PendingIntent.getService() line isn't working. How do I fix this issue? Thanks! :D
I want to launch a notification. When I click on it, it opens a NEW window of the app.
Here's my code:
public class Noficitation extends Activity {
NotificationManager nm;
static final int uniqueID = 1394885;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent= new Intent (Intent.ACTION_MAIN);
intent.setClass(getApplicationContext(), SchoolBlichActivity.class);
PendingIntent pi=PendingIntent.getActivity(this, 0, intent, 0);
String body = " body";
String title = "title!";
Notification n =new Notification(R.drawable.table, body, System.currentTimeMillis());
n.setLatestEventInfo(this, title, body, pi);
n.defaults = Notification.DEFAULT_ALL;
n.flags = Notification.FLAG_AUTO_CANCEL;
nm.notify(uniqueID,n);
finish();
}
by the way, if i add nm.cancel(uniqueID) before the finish(), it creates the notification and immediately deletes it...
Thanks for the help :D
You might want to just add a notification in the notification bar, and when the user clicks it, it will launch the actual Activity. This way the user won't be interrupted in whatever he's doing.
Create the status bar notification like this:
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.notification_icon, "Hello", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, myclass.class);
notification.setLatestEventInfo(getApplicationContext(), "My notification", "Hello world!", notificationIntent, PendingIntent.getActivity(this, 0, notificationIntent, 0));
mNotificationManager.notify(1, notification);
http://developer.android.com/guide/topics/ui/notifiers/notifications.html
Are you just trying to open a notification window in a current activity? Because if you are I dont think you need to launch it with an intent. You normally only use intents to launch new services or activities in your app unless youve built a custom view and activity/service which is to take place within the notification box. I see you have it set up in its own class which is fine but I think the way your doing it by default would open an entire new view.
If you need to launch a notification during a process or something like a button click you dont need to have the intent there.....or at least I never did :) What exactly are you trying to achieve with the notification.