I can't seem to be able to create an Android Wear notification that updates with out blinking the app icon whereas the same code works fine on an Android phone.
Most referenced solutions talk about updating the same notification, use setAlertOnlyOnce, keeping the ID or when the same. However, whatever I do, every time the notification is updated it blinks (most noted by the App Icon).
As suggested here Android Wear: Timer like notification card on wear device you can use setHintHideIcon(true) to hide the app icon, which hides the blinking part, however in the limited world of Android Wear Notifications the app icon plays a large part in the branding of the application.
If you want a timer, you can use .setUsesChronometer(true) and let the system update the timer which works perfectly. Unfortunately if you want to update something else than time (like steps or messages received count) it seems to me you're out of luck.
Below you can find code that works fine when run as a phone app, but blinks when run as a wearable app.
Commented line below to demonstrate that the notification still blinks (when running on wear, not the phone) that the notification still blinks when posting an unchanged notification on the wearable. Uncomment to update the notification again.
mNotification = buildNotification(WearMainActivity.this);
Therefore my question is if anyone has any further idea's we can explore to keep the notification from blinking or if we can write this down as an Android Wear bug?
public class WearMainActivity extends Activity {
public final int NOTIFICATION_ID= 1;
public Notification mNotification;
public int count;
public long when;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
count = 0;
when = System.currentTimeMillis();
mNotification = buildNotification(WearMainActivity.this);
postDelayedHandler();
finish();
}
private void postDelayedHandler(){
new Handler().postDelayed(new Runnable() {
public void run() {
count++;
mNotification = buildNotification(WearMainActivity.this);
NotificationManager notifyMgr = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
notifyMgr.notify(NOTIFICATION_ID, mNotification);
postDelayedHandler();
}
}, 1000L);
}
private Notification buildNotification(Context context){
return new Notification.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(context.getString(R.string.app_name))
.setContentText("Count: "+count)
.setWhen(when)
// .setOngoing(true) //Don't do this, adds "Mute app" action
.setOnlyAlertOnce(true)
.setPriority(Notification.PRIORITY_MAX)
.extend(new Notification.WearableExtender()
// .setHintHideIcon(true) //Hides the icon, so kinda hides the blink
)
.build();
}
}
Tested on:
Wearable: Moto 360 (4.4W2) Wear Emulator (5.0.1)
Phones: Galaxy Nexus (4.3) and Nexus 5 (5.0.0)
Occurs: When running as a Wearable app or as phone notification displayed on Wearable. Works perfect on phone.
Referenced questions:
How can I avoid blinking notification update while changing button
Updating an ongoing notification quietly
How to properly update a notification post api 11?
Replace:
NotificationManager notifyMgr =
((NotificationManager)getSystemService(NOTIFICATION_SERVICE));
to:
NotificationManagerCompat notifyMgr =
NotificationManagerCompat.from(this);
More informations: https://developer.android.com/training/wearables/notifications/creating.html
You also making a lot of updates. Every update is send via bluetooth to Wear. You should create self-install app to Android Wear. The delay of sending is about 3 seconds.
I solved this problem a while back when I was working with Android Wear but the code in unfortunately gone. Anyway, what I did was to not BUILD the notification every time I wanted to update it, I just tagged the notification the first time I created it and then I retrieved it with the TAG and made my changes directly to that object. That completely stopped the flickering...
Related
As part of my assignment I want to remove a notification that has been received but not been interacted with after a certain amount of time. This means if the notification is still in the notification tray after this amount of time, the app will delete it automatically.
For foreground notifications this wasn't the issue, as I applied the following code:
void SendNotification(RemoteMessage remotemessage)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);
long[] pattern = { 100, 100, 100, 100 };
var notificationBuilder = new Notification.Builder(this)
.SetVibrate(pattern)
.SetSmallIcon(Resource.Drawable.mhu2)
.SetContentTitle(remotemessage.GetNotification().Title)
.SetContentText(remotemessage.GetNotification().Body)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager)GetSystemService(Context.NotificationService);
int id = 0;
notificationManager.Notify(id, notificationBuilder.Build());
Handler handler = new Handler(Looper.MainLooper);
long delayInMilliseconds = 5000;
handler.PostDelayed(new Runnable(() => notificationManager.Cancel(id)), delayInMilliseconds);
}
When a notification is received, it will automatically be removed after 5 seconds (debugging purposes). However, as we all know, notifications are not handled the same depending on the state of the app.
This code works for foreground apps, but will never be run when the app is in the background or killed. So when the user receives a notification when the app was not opened or in the background, the notification will not be removed.
I've tried to look into this and saw partial solutions by executing code when overriding the OnDestroy/OnStop/OnPause state, but that still won't help to remove the notification when the app was never opened.
Any suggestions are greatly appreciated!
I just want to post a quick update as I've been able to solve this issue.
Android handles notification differently based on what is provided within the notification. I found out that if the notification is only build with datafields (so no notification body), the OnMessageReceived() will always be fired regardless of the state of the app. The timer that I realised will fire on foreground, background and app closed states. The only time this doesn't work is when the app is forced stopped, but in my context this won't cause issues.
I am creating notification from my app on Phone in the below way.
private void launchMicroAppFromWearableNotif() {
int notificationId = 001;
// The below action has been defined in the micro app
Intent i = new Intent("com.microapp.action.PLAY_MUSIC");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent playPendingIntent =
PendingIntent.getActivity(this, 0, i, 0);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.play_music)
.setContentTitle("Play Music")
.setContentText("Play Music on Wear")
.setContentIntent(playPendingIntent)
.addAction(R.drawable.play_music, getString(R.string.act1), playPendingIntent);
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(this);
// Build the notification and issues it with notification manager.
notificationManager.notify(notificationId, notificationBuilder.build());
}
I have created a wearable micro app which has an activity(PlayActivity) with action "com.microapp.action.PLAY_MUSIC" defined in wearable Manifest.
When I take the action from notification on the wearable I expect the activity form the micro app to be launched. But nothing happens. Could someone please help on this. Is it the right way to do it?
Actions that you add to a notification are for the device that the notification was created on, so if you create a notification on your phone, when you click on it on your watch, the action will be sent back to your phone to be executed.
If you want to open your activity on your watch, you cannot achieve that by sending a notification from your phone in the manner you have done. You have a couple of options: for example you can send a message from your phone to your watch and then have the wear side of your app catch that message and put out a "local" notification on the watch; then the actions on that notification are local to your watch and you can open your desired activity via the actions in that notification. If you directly want to open an activity on your watch from your phone (i.e. you don't need a notification to show up on your watch), then you can handle the message that I talked about on your watch and instead of creating a notification there, simply open the desired activity.You may find the WearCompanionLibrary useful in handling some of these cases.
I'm changing an existing application to use MediaStyle notifications to provide lock screen music information and transport controls in Android 5.0. It seems, however, that updating such notifications isn't working as expected. The following code snippet generates notifications each time a button is pressed, incrementing a counter displayed in the notification title:
public class MainActivity extends Activity {
private int serial;
private TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView)findViewById(R.id.textView1);
}
public void buttonClick(final View view) {
final Notification.Builder builder = new Notification.Builder(this)
.setContentTitle("Title " + serial)
.setContentText("Text")
.setContentInfo("Info")
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher))
.setOngoing(true)
.setStyle(new Notification.MediaStyle())
.setVisibility(Notification.VISIBILITY_PUBLIC);
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE );
nm.notify(1, builder.build());
text.setText("Serial = " + serial);
serial++;
}
}
The problems are:
When executed in the emulator running 5.0, the notification text in the notification drawer or lock screen is out of sync with the serial displayed in the TextView. If MediaStyle is not set, notifications have correct numbering in the notification drawer, but not in the lock screen.
The MediaStyle notification is displayed correctly in the lock screen, until it's viewed in the notification drawer for the first time. After that, it's not displayed as a MediaStyle notification in the lock screen anymore (but not exactly like a standard, non-MediaStyle notification). Notably, buttons added with addAction() are not displayed anymore, until the emulator is restarted.
So I suspect I'm doing something very wrong (either that, or the Android image running on the emulator is broken, but that seems less likely). Any ideas?
It turned out that the emulator was broken after all. The notification behavior, including updating icons added with addAction(), title and info updates, and notifications in lock screen after being seen in the drawer, is correct in a real device (a Nexus 5 running 5.0). At the time this answer was written, however, the problems still happened in the emulator provided with the API 21 SDK, and no updates were available.
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 have an IntentService that uploads a file. Everything works fine, but I'm a little confused about how to handle the notifications. When I start the notification I use startForeground() because the files can be rather large and I don't want the upload to get killed unless absolutely necessary. When I use startForeground() it displays two notifications in the notification area (one under Ongoing and one under Notifications):
I've read through a number of different Stack Overflow posts and web articles, but none of them answer the question I have...hopefully I haven't missed one that talks about ths.
It's my understanding that the ongoing notification in the image above (the one without the progress bar) is put there since this is running in the foreground (Services documentation). That's all well and good if you ask me, and I understand why. However, I don't need two notifications displayed and I'm pretty sure most people wouldn't want two notifications cluttering up the notification area either. I would like to know how to properly handle the notification so that only one displays and doesn't clutter up the notification area.
The only way I've been able to get around this is if I set the integer ID for startForeground (int id, Notification notification) (ONGOING_NOTIFICATION_ID in my code below) to zero. However, the documentation I quote above says:
Caution: The integer ID you give to startForeground() must not be 0
Setting it to 0 disables the Ongoing notification and then just shows the regular notification with the progress bar. I figure I could kind of "fix" this by setting .setOngoing(true) until it's done uploading the file and then setting .setOngoing(false) once it's finished, so it can be dismissed. I'm not sure exactly how "Cautious" one has to be with setting the integer ID to 0. To me it kind of seems like a lazy way to be able to get around the issue I'm having, but I don't know if there are other consequences for setting it to 0. Also, this only works if I only have one notification that I'm dealing with. If I have multiple, different notifications, then I'll need different IDs for each one and this won't work. Update: It looks like setting the ID to 0 won't work in Android 4.3, so now I'm back to square one.
What is a valid way to get around displaying both notifications?
Update/Solution: Duh, taking some time off and then coming back to this and double-checking what I had done based on #dsandler 's recommendation helped me figure out what I was doing wrong. I wasn't setting the correct ID when I was doing the progress update, so that's why it was creating two notifications and one wasn't getting updated. Using the same ID (ONGOING_NOTIFICATION_ID) for all the notifications solved the issue for me. See the code below for the additional pieces I hadn't included before and where I had made the mistake.
Relevant code from UploadFile.java:
public class UploadFile extends IntentService {
private static final int ONGOING_NOTIFICATION_ID = 1;
#Override
protected void onHandleIntent(Intent intent) {
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentTitle(getText(R.string.upload))
.setContentText("0% " + getText(R.string.upload_in_progress))
.setSmallIcon(android.R.drawable.stat_sys_upload);
startForeground(ONGOING_NOTIFICATION_ID, mBuilder.build());
....
if (progress > 0){
percent = (Long.valueOf(progress) * 100) / totalSize;
mBuilder.setProgress(100, percent.intValue(), false);
mBuilder.setContentText(percent.intValue() + "% " + getText(R.string.upload_in_progress));
mNotifyManager.notify(ONGOING_NOTIFICATION_ID, mBuilder.build()); // <-- My problem was that I had set the ID here to 0 and did not make it the same as the ID I set above
}
....
}
First off, judging by your description, you might be able to get away with a regular service, recognizing that the out-of-memory killer won't come calling unless things are getting dire on the device and your service has really been running a very long time.
That said, if you must make the service foreground, the typical strategy here is to show your progress using the Notification you used when you put your service into the foreground state. Using NotificationManager.notify you can post as many updates to that notification as you like, including adjustments to progress bars via Notification.Builder.setProgress, for example.
In this way you only show one notification to the user, and it's the one required by startForeground.
When you want to update a Notification set by startForeground(), simply build a new notication and then use NotificationManager to notify it.
The KEY point is to use the same notification id.
I didn't test the scenario of repeatedly calling startForeground() to update the Notification, but I think that using NotificationManager.notify would be better.
Updating the Notification will NOT remove the Service from the foreground status (this can be done only by calling stopForground );
Example:
private static final int notif_id=1;
#Override
public void onCreate (){
this.startForeground();
}
private void startForeground() {
startForeground(notif_id, getMyActivityNotification(""));
}
private Notification getMyActivityNotification(String text){
// The PendingIntent to launch our activity if the user selects
// this notification
CharSequence title = getText(R.string.title_activity);
PendingIntent contentIntent = PendingIntent.getActivity(this,
0, new Intent(this, MyActivity.class), 0);
return new Notification.Builder(this)
.setContentTitle(title)
.setContentText(text)
.setSmallIcon(R.drawable.ic_launcher_b3)
.setContentIntent(contentIntent).getNotification();
}
/**
this is the method that can be called to update the Notification
*/
private void updateNotification() {
String text = "Some text that will update the notification";
Notification notification = getMyActivityNotification(text);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(notif_id, notification);
}