I have a count down timer that when it goes off (to zero) it checks to see if the app has focus. If not it launches a notification in the notification bar. When you click on the notification is re-opens the app. Now all of this works fine but if the screen happens to go off, the timer keeps going and the notification is available at the right time but never actually vibrates or rings until i turn the screen back on. Then it displays the notification like it was waiting in a queue or something.
How do I get it so that the notification manager will actually alert the user when the screen is turned off?
Update: If I set the timer for 2 minutes, it takes another 2-3 minutes for the notification to actually work. So it does work but it's on a huge delay!
Code: So I setup the notification service when the app loses focus, and when the MyCount1 is finished is checks if the app has focus and if not it shows the notification. This all works when the screen backlight is on. Once it goes off it is unreliable.
#Override
public void onWindowFocusChanged(boolean hasFocus){
if(hasFocus == false){
mFocusFlag = false;
ns = Context.NOTIFICATION_SERVICE;
mNotificationManager = (NotificationManager) getSystemService(ns);
icon = R.drawable.statusbar;
tickerText = "Check the timer!!!";
when = System.currentTimeMillis();
notification = new Notification(icon, tickerText, when);
context = getApplicationContext();
contentTitle = "Countdown Timer";
contentText = "Click to Check the Timer";
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationIntent = new Intent(this, StartTimer.class);
contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
}else{
mFocusFlag = true;
}
}
public class MyCount1 extends CountDownTimer {
public MyCount1(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
public void onFinish() {
if(mFocusFlag == false){
mNotificationManager.notify(HELLO_ID, notification);
}else{
mVib.vibrate(1000);
}
}
public void onTick(long millisUntilFinished) {
if((millisUntilFinished/1000%60) < 10){
mTime.setText("1st Side = " + millisUntilFinished/60000 + ":0" + (millisUntilFinished / 1000)%60);
}else{
mTime.setText("1st Side = " + millisUntilFinished/60000 + ":" + (millisUntilFinished / 1000)%60);
}
}
}
Now all of this works fine but if the screen happens to go off, the timer keeps going and the notification is available at the right time but never actually vibrates or rings until i turn the screen back on. Then it displays the notification like it was waiting in a queue or something.
How do I get it so that the notification manager will actually alert the user when the screen is turned off?
When the screen turns off, the CPU will stop running shortly thereafter, unless something is holding a WakeLock.
This means one of two things:
You understand all of this and are holding a WakeLock. This may or may not be a good idea, from the standpoint of what users like with their devices (e.g., good battery life). Be that as it may, you may need to hold a stronger WakeLock, one that keeps the screen at least dim. I have not tried raising a Notification while under a WakeLock, so I am uncertain what the rules all are.
You do not understand all of this, and therefore are thinking your timer is going when, in reality, the device has fallen asleep and the CPU has turned off. When the CPU turns back on again, your timer will go off immediately.
Using AlarmManager allows you to do timer-based events that wake up the device, and do not require your code to be hanging around in memory in the meantime. I have no idea what you're trying to do here (seems rather bizarre from your description), but AlarmManager may be something worth investigating as a replacement for your timer.
It probably goes off when the phone is woken up by some other application, for example email application periodically goes to check for new emails. You need to set your own alarm to fire at the time you need. http://developer.android.com/reference/android/app/AlarmManager.html
NotificationManager doesn't have notion of time. It has to be triggered somehow. The problem in your case is that, if you let the phone sleep, it will do just that. Alarms are specifically exist so you can wake up the device when you need to.
Related
In my app I made a service to the foreground and display a notification to the user. By notification.setAutoCancel(false); I set the notification icon always displayed without auto-cancel itself.
Actually I need this service run long period of time and I want to make the user be aware of this(by seeing the notification icon they know the service is still running).
So I wonder whether my hypothesis is correct, as long as the notification icon is displayed, it means the service is still running, and once the notification icon is gone, that means the service is done for some reasons.
Here is the simplified code:
LongLiveService extends Service{
private MyThread thread;
onStartCommand() {
thread.start();
createNotification(this);
}
createNotification(Context context) {
// build a notification
notification.setAutoCancel(false);
startForeground.invoke(this, notificationID, notification.build());
}
}
MyThread extends Thread{
run() {
// doing something all the time
}
}
You wrote:
once the notification icon is gone, that means the service is done for some reasons.
If you want your notification to stay in the status bar as long as the Service is running, you need to make the notification persistent via the flag FLAG_ONGOING_EVENT, so it can't be dismissed:
Notification notification = new Notification(...);
PendingIntent pendingIntent = PendingIntent.getActivity(..., Notification.FLAG_ONGOING_EVENT);
notification.flags = Notification.FLAG_ONGOING_EVENT;
notification.setLatestEventInfo(..., pendingIntent);
mNotificationManager.notify(1, notification);
I have an application that has a reminder feature. When it's time to remind the user of something, my application creates a notification, possibly using FLAG_INSISTENT to ensure the alarm is heard. Once the user interacts with my app to acknowledge the alarm, the app cancels the notification.
The user can launch the app either by pulling down the notification bar and tapping on my notification -- in which case everything is fine -- or by navigating to the app some other way, such as by launching it from the home screen. If the user uses the notification bar method, the FLAG_INSISTENT audio stops when the user touches the notification bar. But here's the problem: if the user enters the app directly without touching the notification bar. the audio for the FLAG_INSISTENT alarm keeps playing indefinitely -- even after my app cancels the notification. The only way a user can stop it is to pull down the notification bar (or reboot the device!).
I've been getting tons of bug reports from angry users ever since the optional FLAG_INSISTENT feature went live. It doesn't seem specific to one platform; users reporting this bug have hardware including a Motorol Razr Maxx HD, Samsung Galaxy Note, and HTC EVO 4G LTE. I've had frustrated users report that they resorted to uninstalling the app to stop the noise, and even then said it wouldn't stop. Searching the web has been fruitless.
The notifications are being created in more-or-less the garden variety way:
notification = new Notification(
R.drawable.icon,
message,
System.currentTimeMillis()
);
if (userDefinedaCustomSound) {
notification.sound = Uri.parse(userSelectedReminderSound);
} else {
notification.defaults |= DEFAULT_SOUND;
}
notification.ledARGB = 0xff00ff00;
notification.ledOnMS = 300;
notification.ledOffMS = 1000;
notification.flags |= Notification.DEFAULT_VIBRATE;
if (userWantsContinuousAlarm) {
notification.flags |= Notification.FLAG_INSISTENT;
}
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NOTIFICATION_BAR_ID, notification);
And are being cancelled thusly:
nm.cancel(NOTIFICATION_BAR_ID);
I've tried adding the FLAG_AUTO_CANCEL to the notification; that has no effect. As a workaround, I've also tried modifying my cancel method so that it first issues a new notification with no sound, and without FLAG_INSISTENT, then cancels; again, the audio just keeps on playing.
Any ideas?
I faced the same problem. The audio keep on playing after the notification was cancelled.
I formulated this work around,
Perform a normal notification cancelled.mNotificationManager.cancel(getNotificationID(event));
Immediately Create another notification with sound. Use the default Alarm.
Immediately cancel the notification.
Note:
The sound played as part of the notification was not the default.
method getNotificationID(event) always return the same constant for the same event object type.
Notification with sound played using the default will stop when the notification is cancelled.
I set the sound using builder using this
setSound(Uri.parse(this.sharedPreferences.getString(key,"")))
From the observations, I think it might be a bug. The reference to the ringtone object was not properly retained so when the cancel was called, it failed to call on the ringtone .stop() or was unable to do so.
Hope you can used it too.
NotificationManager mNotificationManager = (NotificationManager) this.getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel(getNotificationID(event));
audioAlarmTriggered.remove(event.sensortype);
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
builder.setAutoCancel(true)
.setSound(ringtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM));
mNotificationManager.notify(getNotificationID(event), builder.build());
mNotificationManager.cancel(getNotificationID(event));
If above code is in your service class. Then I think the problem is when you open app directly instead using notification bar, that time its not calling your service class else you need to call nm.cancel(NOTIFICATION_BAR_ID); from the activity which opens while clicking on notification.
And to do so you need a global class which keeps static NOTIFICATION_BAR_ID, so that will be helpful to you for managing cancel method.
I hope, this will solve your problem.
I'm trying to turn the LED-flashing on for my activity in foreground, but it works only when the screen is off.
Is it possible to turn the LED on for active activity with the screen on?
My code:
protected void led() {
Notification notif = new Notification();
notif.ledARGB = 0xFF0000ff;
notif.flags = Notification.FLAG_SHOW_LIGHTS | Notification.FLAG_ONGOING_EVENT;
notif.ledOnMS = 800;
notif.ledOffMS = 200;
notificationManager.notify( LED_NOTIFICATION_ID, notif );
}
At first Android LED indicator is very hardware dependent. Second - there is no API for managing LED instead of Notification class with its FLAG_SHOW_LIGHTS flag and several flags for managing flash duration and LED color which you use. Notification is a message you can display to the user outside of your application's normal UI the primary purpose of LED indicator is to present additional notification information for the user when the screen is off. So the answer is definite NO. The LED will only start flashing if your screen is off and it’ll stop when you turn it back on. And there is no way to turn on and off LED when you want and to turn it when any of the application activities is in foreground, because it is managed by the OS internally.
I'm trying to run a service which gives notification, if available every few minutes. Since the service will get destroyed after few hours, I thought of making it foreground service. But if I do so, it shows two notification. One is notification column(Thats what I need and got). Another one on Ongoing column which shows icon that work go at all. Its really annoying. The notification code goes like this
Notification.java
n.setLatestEventInfo(getApplicationContext(), "Update", "new update arrived", pIntent);
n.flags = Notification.FLAG_AUTO_CANCEL;
startForeground(2233,n);
n.flags |=Notification.FLAG_NO_CLEAR;
NM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NM.notify(id,n);
You have to have an ongoing notification to use a foreground so that the user can know it's active. You could schedule an alarm with AlarmManager to start up your service when needed instead of keeping it alive the whole time. You can then do your check at whatever interval you'd like, and your notification will stay alive even if the service closes.
So I have indeed searched thoroughly for an answer to my question; normally I can find answers pretty easily to pretty much anything.
Anyway, basically I have an alarm manager set up which eventually sets a broadcast receiver. Inside the receiver, it decides which intent has been received, removes a shared preference, and then sets a notification that starts the activity. The problem is that on my phones with 4.0 the shared preference item is not successfully deleted, but on any previous phones I've tried (2.2, 2.3) it works perfectly.
I did end up finding the documentation of Android 3.1 and the FLAG_INCLUDE_STOPPED_PACKAGES implementation. I tried throwing that onto the intent, just in case, but it still wasn't working. Either way, it's not the launching of the activity that is the problem, but the simple deletion of a shared preference.
I hope that's clear enough! I'll put in some of the code below.
This is where the intent is started:
Calendar cal = Calendar.getInstance();
int seconds = 5 * 60; // 1 * 24 * 60 * 60;
cal.add(Calendar.SECOND, seconds);
Intent intent = new Intent(SetAlertActivity.this, ReminderReceiver.class);
intent.putExtra("id", "FAlert");
//intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), FRAUD_ALERT_CODE, intent, 0);
AlarmManager alertManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alertManager.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
settingsEditor = alertSettings.edit();
settingsEditor.putLong("AlertTime1", cal.getTimeInMillis());
settingsEditor.commit();
And then the broadcast receiver onReceive():
nContext = context;
alertSettings = nContext.getSharedPreferences(MainActivity.PREFERENCE_FILENAME, 0);
if (intent.getStringExtra("id").equals("FAlert"))
{
settingsEditor = alertSettings.edit();
settingsEditor.remove("AlertTime1");
settingsEditor.commit();
String ns = Context.NOTIFICATION_SERVICE;
int icon = R.drawable.ar_icon;
CharSequence tickerText = nContext.getString(R.string.notification_ticker);
CharSequence contentTitle = nContext.getString(R.string.notification_title);
CharSequence contentText = nContext.getString(R.string.notification_text);
long when = System.currentTimeMillis();
NotificationManager mNotificationManager = (NotificationManager) nContext.getSystemService(ns);
Notification notification = new Notification(icon, tickerText, when);
Intent notificationIntent = new Intent(nContext, SetAlertActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(nContext, 135, notificationIntent, 0);
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_LIGHTS;
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(nContext, contentTitle, contentText, contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, notification);
}
So, as I mentioned before, on my devices on 4.0 (I don't have any 3.X devices) the
settingsEditor = alertSettings.edit();
settingsEditor.remove("AlertTime1");
settingsEditor.commit();
part isn't working. The activity will open correctly, but the "AlertTime1" is still there. On the 2.2 and 2.3 devices, the "AlertTime1" is successfully deleted.
sigh :D
Thanks for any help!!
Oh, and in case it's needed, here is my manifest for the receiver:
<receiver
android:name="ReminderReceiver"
android:process=":remote" >
</receiver>
This is where the difference shows:
alertSettings = getSharedPreferences(AlertRenewActivity.PREFERENCE_FILENAME, 0);
settingsEditor = alertSettings.edit();
if (alertSettings.contains("AlertTime1"))
{
alertTime = alertSettings.getLong("AlertTime1", 0);
timeLeft = (int) ((alertTime - System.currentTimeMillis()) / (1000L));
daysLeft = timeLeft / (60 * 60 * 24);
daysLeftView.setText(Integer.toString(daysLeft));
setAlert.setEnabled(false);
setAlert.setTextColor(R.color.dark_text);
}
else
{
daysLeftView.setText(R.string.no_alert_set);
}
On my older phones, it correctly resets to saying "No Alert Set" but on the 4.0 phones it still shows "0" days left (which is what it says since I'm only setting the alert to 5 minutes or so for testing). Basically, the user can't set a new alert because it hasn't reset correctly, and again, only on the 4.0 phones I'm trying :P
Use Context.MODE_MULTI_PROCESS as the 2nd parameter to getSharedPreferences(). The problem is that you have the broadcast receiver running in a separate process from your activities, and as of Android 3.0 the default behaviour of multi-process access to shared preferences has changed. This should fix the problem for you on 4.x devices.
However, there is a bug in Android 2.3 which causes simultaneous access to shared preferences from multiple processes not to work reliably in some cases. We came across this and were very frustrated by it because it is difficult to reproduce and explain (probably some kind of timing issue).
What I ended up doing was just having a check in the activity itself that says "if the alarm time is less than 0, delete the alarm time." It was a work around; I didn't receive any other answer that worked unfortunately.
you should delete android:process=":remote" attribute in your receiver in the manifest. SharedPreferences does not work with new processes and :remote declares "do whatever the process id is ".
I know this is an old question but maybe my answer will be helpful for others who facing this problem this days. I just found a solution and it worked for me.
make a service and implement the work you want on it, and then just call the service from your broadcast receiver, which means the only work of your receiver is to call the service which will handle the work you want to do.
The simply answer is this: don't bother doing so much in a receiver. Instead, kick of an intent call to another Activity in the same package hierarchy and you'll be able to do it just as easily.