I have an app where i'm having some issues with notifications not being consistent on different devices. The notification is used by a foreground service
This is what my notification looks like in my pixel3 api29 emulator
Because of the issue i'm troubleshooting, I decided to extract the code and put it in a dummy app that would let me simulate the triggering event more easily. However, after doing that and running on the exact same pixel3 api29 emulator, i realized the notification is not even consistent on the same device. In the dummy app for a dummy foreground service the notification looks like this
I can't find what's driving the different look of the action buttons in the two apps. Even the behaviour is different. In the first version, the floating headsup notification stays there forever until i clear it programatically but in the second dummy app the notification clears itself after 6 seconds. I tried using the same theme in both, added the exact same dependency versions thinking that i was pulling different versions of the notification library but nothing, the code to create the notifications is the same in both:
private Notification createIncomingCallNotification(Intent intent) {
Intent hangupIntent = new Intent(this, getClass());
hangupIntent.setAction("hangup");
PendingIntent hangupPendingIntent = PendingIntent.getService(this, 1244, hangupIntent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Action hangupAction = new NotificationCompat.Action.Builder(0, getActionText(R.string.hangup_button_label, R.color.test1), hangupPendingIntent).build();
Intent uiIntent = new Intent(this, VideoCallActivity.class);
uiIntent.putExtras(intent);
uiIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0, uiIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action previewAction = new NotificationCompat.Action.Builder(0, getActionText(R.string.preview, R.color.test2), fullScreenPendingIntent).build();
String caller = "Caller guy";
Log.v(TAG, "Creating incoming call notification from " + caller);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, ChannelIds.INCOMING_CALL_CHANNEL_ID)
.setContentTitle(getString(R.string.incoming_call_notification_title, caller))
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setSmallIcon(R.drawable.ic_white_100dp)
.addAction(hangupAction)
.addAction(previewAction)
.setOnlyAlertOnce(true)
.setFullScreenIntent(fullScreenPendingIntent, true);
return notificationBuilder.build();
}
private Spanned getActionText(#StringRes int stringRes, #ColorRes int colourRes) {
Spannable spannable = new SpannableString(getText(stringRes));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
// This will only work for cases where the Notification.Builder has a fullscreen intent set
// Notification.Builder that does not have a full screen intent will take the color of the
// app and the following leads to a no-op.
spannable.setSpan(new ForegroundColorSpan(getColor(colourRes)), 0, spannable.length(), 0);
}
return spannable;
}
Does anyone know what can cause this inconsistency even on the same device?
I finally figured it out. What changes the headsup notification is this permission in the manifest
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
Related
I am trying to create a notification with a cancel button, but when I click on it nothing happens. This is my code:
private NotificationCompat.Builder notificationBuilder;
public void createNotification() {
notificationBuilder = new NotificationCompat.Builder(service);
notificationBuilder.setProgress(100, 0, false);
notificationBuilder.setAutoCancel(true);
Intent intent = OrderProcessingService_.intent(service).actionCancelUpload(basket.getPhotobook_id()).get();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getService(service, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
notificationBuilder.setContentIntent(pendingIntent);
notificationBuilder.setSmallIcon(R.drawable.ic_action_file_cloud_upload);
NotificationCompat.Action cancelAction = new NotificationCompat.Action(R.drawable.ic_action_navigation_close, service.getString(R.string.cancel_upload), pendingIntent);
notificationBuilder.setContentTitle(service.getString(R.string.notification_upload_title));
notificationBuilder.setContentText(service.getString(R.string.notification_uploading_subtext, Util.getTitle(basket.getPhotobook())));
notificationBuilder.addAction(cancelAction);
addBigPicture(notificationBuilder);
service.startForeground(1, notificationBuilder.build());
}
You will have to keep notification id and then call
NotificationManager nMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nMgr.cancel(notification );
I am glad to post it! After working all night I found something. So, here we go!
Create an xml layout file for your notification.
Create the notification using the Notification.Builder. After adding everything you want (icons, sounds, etc) do this:
//R.layout.notification_layout is from step 1
RemoteViews contentView=new RemoteViews(ctx.getPackageName(), R.layout.notification_layout);
setListeners(contentView);//look at step 3
notification.contentView = contentView;
Create a method setListeners. Inside this method you have to write this:
//HelperActivity will be shown at step 4
Intent radio=new Intent(ctx, packagename.youractivity.class);
radio.putExtra("AN_ACTION", "do");//if necessary
PendingIntent pRadio = PendingIntent.getActivity(ctx, 0, radio, 0);
//R.id.radio is a button from the layout which is created at step 2
view.setOnClickPendingIntent(R.id.radio, pRadio);
//Follows exactly my code!
Intent volume=new Intent(ctx, tsapalos11598712.bill3050.shortcuts.helper.HelperActivity.class);
volume.putExtra("DO", "volume");
//HERE is the whole trick. Look at pVolume. I used 1 instead of 0.
PendingIntent pVolume = PendingIntent.getActivity(ctx, 1, volume, 0);
view.setOnClickPendingIntent(R.id.volume, pVolume);
For my requirements I used a HelperActivity which responds to the intents. But for you I don't think it is necessary.
If you want the full source code you can browse it or download it from my git repo. The code is for personal use, so don't expect to read a gorgeous code with a lot of comments. https://github.com/BILLyTheLiTTle/AndroidProject_Shortcuts
ALL THE ABOVE, ANSWERS THE QUESTION OF CATCHING EVENT FROM DIFFERENT BUTTONS.
About canceling the notification I redirect you here
How to clear a notification in Android
Just remember to use the id you parsed at the notify method when you called the notification for fist time
Source : Android notification with buttons on it
I am using MediaPlayer in my app. I am adding an Ongoing Notification with media player controls (such as previous, next and stop buttons) in my app, so that users don't have to go in the app to access those controls. It looks fine on platforms 4.x. Here is the screenshot of the notification on Android 4.2.2.
But, on Android 2.2, it looks like this:
My code is as follows:
private Notification generateNotification() {
Log.d(TAG, "generateNotification called");
Intent actionIntent = new Intent(getApplicationContext(),
AartiActivity.class);
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(),
0, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews mNotificationView = new RemoteViews(getPackageName(),
R.layout.notification_view);
NotificationCompat.Builder builder = new NotificationCompat.Builder(
getApplicationContext());
builder.setSmallIcon(R.drawable.icon);
builder.setContent(mNotificationView);
builder.setOngoing(true);
builder.setTicker("Aarti Sangrah");
builder.setContentIntent(pi);
mNotificationView.setImageViewResource(R.id.imgAppIc, R.drawable.icon);
mNotificationView.setTextViewText(R.id.txtAartiPlaying, mediaName);
return builder.build();
}// generateNotification
And then, I called startForeground(1, generateNotification()); in onPrepared().
The Remote Views is available since API level 1. And, it is well supported also. I read somewhere, it was not supported prior to Honeycomb. But, on several devices having Android 2.x, this feature is available. Also, in order to check this, I looked at the source code of Music Player of Android 2.2 from here.
Here, is the snippet from its Music Player Service.
RemoteViews views = new RemoteViews(getPackageName(),
R.layout.statusbar);
views.setOnClickPendingIntent(R.id.btnTest, PendingIntent
.getActivity(getApplicationContext(), 0,
new Intent(getApplicationContext(),
MusicBrowserActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT));
views.setImageViewResource(R.id.icon,
R.drawable.stat_notify_musicplayer);
if (getAudioId() < 0) {
// streaming
views.setTextViewText(R.id.trackname, getPath());
views.setTextViewText(R.id.artistalbum, null);
} else {
String artist = getArtistName();
views.setTextViewText(R.id.trackname, getTrackName());
if (artist == null || artist.equals(MediaStore.UNKNOWN_STRING)) {
artist = getString(R.string.unknown_artist_name);
}
String album = getAlbumName();
if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) {
album = getString(R.string.unknown_album_name);
}
views.setTextViewText(
R.id.artistalbum,
getString(R.string.notification_artist_album, artist,
album));
}
Notification status = new Notification();
status.contentView = views;
status.flags |= Notification.FLAG_ONGOING_EVENT;
status.icon = R.drawable.stat_notify_musicplayer;
status.contentIntent = PendingIntent.getActivity(this, 0,
new Intent("com.android.music.PLAYBACK_VIEWER")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);
startForeground(PLAYBACKSERVICE_STATUS, status);
The Remote Views has been used in this code. It had two TextViews. I modified the code by adding a button to it, and also performed action on button click. Everything worked fine on every platform.
Same thing, I want with my application. But, on 2.2, it looks as I had shown above in the screenshot. I thought it is because of white colors text and button so tried changing the colors of button and text, but no luck. As far as I understand, only thing I figured out is remote view is not inflated on Android 2.2 (in my case). I am not getting why notification is not appearing properly on Android 2.x platforms.
I solved my problem. Here is my solution.
private Notification generateNotification() {
Log.d(TAG, "generateNotification called");
Intent actionIntent = new Intent(getApplicationContext(),
AartiActivity.class);
PendingIntent pi = PendingIntent.getActivity(getApplicationContext(),
0, actionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews mNotificationView = new RemoteViews(getPackageName(),
R.layout.notification_view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(
getApplicationContext());
builder.setSmallIcon(R.drawable.icon);
builder.setContent(mNotificationView);
builder.setOngoing(true);
builder.setTicker("Aarti Sangrah");
builder.setContentIntent(pi);
mNotificationView.setImageViewResource(R.id.imgAppIc,
R.drawable.icon);
mNotificationView.setTextViewText(R.id.txtAartiPlaying, mediaName);
mNotificationView.setTextColor(R.id.txtAartiPlaying, getResources()
.getColor(android.R.color.holo_orange_light));
return builder.build();
} else {
mNotificationView.setTextViewText(R.id.txtAartiPlaying, mediaName);
mNotificationView.setTextColor(R.id.txtAartiPlaying, getResources()
.getColor(android.R.color.holo_orange_light));
Notification statusNotification = new Notification();
statusNotification.contentView = mNotificationView;
statusNotification.flags |= Notification.FLAG_ONGOING_EVENT;
statusNotification.icon = R.drawable.icon;
statusNotification.contentIntent = PendingIntent.getActivity(this,
0, new Intent(getApplicationContext(), AartiActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);
return statusNotification;
}
}// generateNotification
But, I am quiet surprised. NotificationCompat.Builder is available in support package and it has been provided for backward compatibility. But, in my case it is working only on Honeycomb and above. As per this section:
Not all notification features are available for a particular version, even though the methods to set them are in the support library class NotificationCompat.Builder. For example, action buttons, which depend on expanded notifications, only appear on Android 4.1 and higher, because expanded notifications themselves are only available on Android 4.1 and higher.
But, I don't think that, this is applicable for my case. NotificationCompat.Builder works with remote views but didn't worked on 2.x(at least in my case, may be I am wrong or missing something). If anybody has any information or resources in this regard, please share it so that I can figure out my mistake.
I have edited the code by using setOnClick pending intent, and this code works for ImageView and notifications text seperate as I want, but I still need some help.
I want to pause or play mediaplayer from my service class, so how could I access the stop or play method of service from Notification pending intent?
Some says broadcast receivers will help you, but I don't get exactly how it's going to work.
I have managed to open a web browser from the pause button from notification, but I don't know how to access service methods. Share any sample code if you have some.
#SuppressWarnings("deprecation")
void showNotification() {
int pendingRequestCode = 0;
int pendingFlag = 0;
final Resources res = getResources();
final NotificationManager notificationManager = (NotificationManager) getSystemService(
NOTIFICATION_SERVICE);
Intent intent = new Intent(this,MainActivity.class);
PendingIntent pi= PendingIntent.getActivity(this, 0, intent, 0);
Notification.Builder builder = new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_action_search)
.setAutoCancel(true)
.setTicker("this is notification")
.setContentIntent(pi);
// Sets a custom content view for the notification, including an image button.
RemoteViews layout = new RemoteViews(getPackageName(), R.layout.notification);
layout.setTextViewText(R.id.notification_title, getString(R.string.app_name));
Intent clickIntent = new Intent(Intent.ACTION_VIEW, Uri_myBlog);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),pendingRequestCode, clickIntent, pendingFlag);
layout.setOnClickPendingIntent(R.id.notification_button,pendingIntent);
builder.setContent(layout);
// Notifications in Android 3.0 now have a standard mechanism for displaying large
// bitmaps such as contact avatars. Here, we load an example image and resize it to the
// appropriate size for large bitmaps in notifications.
Bitmap largeIconTemp = BitmapFactory.decodeResource(res,
R.drawable.pause);
Bitmap largeIcon = Bitmap.createScaledBitmap(
largeIconTemp,
res.getDimensionPixelSize(android.R.dimen.notification_large_icon_width),
res.getDimensionPixelSize(android.R.dimen.notification_large_icon_height),
false);
largeIconTemp.recycle();
builder.setLargeIcon(largeIcon);
notificationManager.notify(NOTIFICATION_DEFAULT, builder.getNotification());
}
PendingIntent getDialogPendingIntent(String dialogText) {
return PendingIntent.getActivity(
this,
dialogText.hashCode(), // Otherwise previous PendingIntents with the same
// requestCode may be overwritten.
new Intent(ACTION_DIALOG)
.putExtra(Intent.EXTRA_TEXT, dialogText)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
0);
}
You did not tell what version of Android you target, but in general it is not possible until Android 3.x (Honeycomb). So if you want that to happen on 2.x, then sorry - you are out of luck.
For Honeycomb, you simply have to provide a custom layout and assign PendingIntent to each button you need, by calling setOnClickPendingIntent(). If you got the SDK's samples downloaded, then see MainActivity of the HoneycombGallery app (shall be in your <SDK>\samples\android-XX\HoneycombGallery\ folder. XX is anything from 14 (or higher).
Check Bound Services using Messenger
http://developer.android.com/guide/components/bound-services.html
Also you can check this question
Binding to a local Service from a BroadcastReceiver
I'm trying to get my Notification to not cancel when the user presses "Clear All" So far I have the intent working properly on everything except this:
Intent intent = new Intent(getBaseContext(), MainActivity.class);
intent.addFlags(Notification.FLAG_ONGOING_EVENT);
intent.addFlags(Notification.FLAG_NO_CLEAR);
PendingIntent contentIntent = PendingIntent.getActivity(
getBaseContext(), 0, intent, 0);
The question I have at this point is: Are my flags correct?
Yes, your flags look pretty much correct, although I don't know if you even need the FLAG_NO_CLEAR. I currently have an app which creates an ongoing (non-cancellable) notification - I only use the FLAG_ONGOING_EVENT and it works fine for me. I pretty much just copied it from a tutorial and then added the ongoing event flag.
Here's some sample code:
String text = "notification";
Notification notification = new Notification(R.drawable.icon, text,
System.currentTimeMillis());
//launch the activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent().setComponent(ComponentName.unflattenFromString("com.example/com.example.MyActivity")), 0);
// set the label and text...
notification.setLatestEventInfo(this, getText(R.string.notification_label),
text, contentIntent);
notification.flags = Notification.FLAG_ONGOING_EVENT;
// Send the notification.
// We use a string id because it is a unique number. We use it later to cancel.
NotificationManager mNM;
mNM.notify(R.string.notification_label, notification);
I've been fighting this for over a week now, so any help would be appreciated.
I have an Activity starting a Service for media playback. Once playback has begun, the Service starts an Ongoing, Non-Cancellable Notification as such:
realIntent = new Intent(this, EpisodeViewer.class);
realIntent.putExtra("show_name", showName);
realIntent.putExtra("episode_name", episodeName);
pendingIntent = PendingIntent.getActivity(this, 0, realIntent, 0);
note =
new Notification(
R.drawable.ic_notification_bcn,
episodeName,
System.currentTimeMillis());
note.flags =
note.flags |
Notification.FLAG_FOREGROUND_SERVICE |
Notification.FLAG_NO_CLEAR |
Notification.FLAG_ONGOING_EVENT;
note.setLatestEventInfo(this, "", episodeName, pendingIntent);
note.contentView =
new RemoteViews(
getApplicationContext().getPackageName(),
R.layout.episode_player_note);
note.contentView.setImageViewResource(
R.id.player_note_icon,
R.drawable.ic_notification_bcn);
note.contentView.setTextViewText(
R.id.player_note_text,
episodeName);
note.contentView.setProgressBar(
R.id.player_note_progress, 100, 0, false);
noteManager.notify(MEDIA_PLAYER_NOTIFY_ID, note);
And this works just fine. When the user switches to play something else (through the Activity's UI) the Service updates the Notification (using the same as above) to change the name and re-set the progress bar. And this works just fine. And as the media progresses, the progress bar in the Notification updates, and this works as well.
But when the media ends or the User wants to stop, the Service tries to cancel the Notification with
noteManager.cancel(MEDIA_PLAYER_NOTIFY_ID);
But this is ignored. There are no errors in the DDMS log, but from my trace I know for sure the cancel is being called. I've tried cancelling the PendingIntent before cancelling the Notification, but this makes no difference. I've also tried replacing the Notification with an 'Empty' one - clearing the progress and the name - and then cancelling. The new 'Cleared' Notification shows, but then still does not cancel.
So what am I missing here? Is there something else that needs to be done to cancel a FOREGROUND or NO_CLEAR or ONGOING Notification that I'm missing? I've tried this with the Emulator under 2.1 and 2.2, and on my hardware running 2.3, all of which exhibit the exact same behaviour.
I noticed the same problem.
If the notification flag has "Notification.FLAG_FOREGROUND_SERVICE" in it, the only way to get rid of it is to call "stopForeground()", but there is a catch. The "stopForeground()" won't remove the notification (with FLAG_FOREGROUND_SERVICE) if "startForeground()" has not been called!
In simple words, if you use FLAG_FOREGROUND_SERVICE, you have to call "startForeground()" and "stopForeground()"!
If "startForeground()" is used, I don't see a reason for putting FLAG_FOREGROUND_SERVICE in the other notifications. But if it is needed, here is a sample (used in public class CLASS extends Service) :
public int onStartCommand(Intent intent, int flags, int startId) {
PendingIntent notifIntent;
Intent notificationIntent = new Intent(); // fill up yourself
notifIntent = PendingIntent.getActivity(); // fill up yourself
Notification note = new Notification(); // fill up yourself
note.setLatestEventInfo(context, getString(R.string.app_name), Message, notifIntent);
startForeground(yourOwnNumber, note); // fill up yourself
displayYourNotification();
// Fill up the rest yourself.
}
public void onDestroy() {
stopForeground(); // fill up yourself
}
public void displayYourNotification() {
Intent notificationIntent = new Intent(); // fill up yourself
notifIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
Notification note = new Notification(); // fill up yourself
note.flags = Notification.FLAG_FOREGROUND_SERVICE;
note.setLatestEventInfo(context, TITLE, Message, notifIntent);
notifManager.notify(ID, note);
}