How can I make a custom Notification? - android

I have been struggling in these last two days to find a way to make a custom android notification. I have passed by the remote views solution but this solution is very limited to changing the layout only. What I need is to put a custom view(other than text views, image views, and these typical views that are usually seen in a notification) in a notification. Is that possible?

but this solution is very limited to changing the layout only
I do not know what you mean by this. The RemoteViews can certainly have more than a layout manager (e.g., LinearLayout); otherwise, it would pointless.
What I need is to put a custom view(other than text views, image views, and these typical views that are usually seen in a notification) in a notification. Is that possible?
You are welcome to try whatever RemoteViews supports, minus the AdapterView subclasses (e.g., ListView). Interactive widgets, such as buttons, will be unreliable, particularly on Android 1.x/2.x, as vendor customizations to the notification tray sometimes prevent interactive widgets from working properly.

A simplest example of custom notification
private void showCustomeNoti() {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
this).setSmallIcon(R.drawable.ic_launcher);
RemoteViews mContentView = new RemoteViews(getPackageName(),
R.layout.custome_notification_layout);
mBuilder.setContent(mContentView);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(100, mBuilder.build());
}
Call this function when you want to show custom notification.

Related

Customizing full screen intent notifications android

Project Target API 30 Android 10, Min API 19 KitKat
I am creating a parental control app where parents can restrict certain apps.
I have a foreground service where I would I ideally trigger an activity-like notification from the service that would envelop the user's entire screen or take them to the home screen.
I have learned that starting activities, including going to the home screen, is no longer possible under normal circumstances as of API 29. https://developer.android.com/guide/components/activities/background-starts
After reading the documentation it seems creating a full screen intent notification is the most highly recommended workaround to the activity restriction.
I am currently working with the following code for my full screen intent notification:
Intent blockedIntent = new Intent(App.getContext(), BlockedItemReceiver.class);
blockedIntent.putExtra("currentApp", restrictedApp.name);
PendingIntent pendingBlockedIntent = PendingIntent.getActivity(App.getContext(), 50, blockedIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder blockedNotificationBuilder = new NotificationCompat.Builder(App.getContext(), CHANNEL_BLOCKED_FROM_ITEM)
.setSmallIcon(R.drawable.ic_baseline_lock_24)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentTitle(restrictedApp.packageName + " was Blocked!")
.setContentText(restrictedApp.name + " will be available again DAY at TIME")
.setCategory(NotificationCompat.CATEGORY_CALL)
.setFullScreenIntent(pendingBlockedIntent, true);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(5, blockedNotificationBuilder.build());
I looked at some documentation for customizing notifications, but the information I found does not have a full screen intent notification example, and when I attempt to add the methods in the documentation example for NotificationCompat.Builder such as setCustomContentView() with custom layouts, my notification fails to appear without an error message.
https://developer.android.com/training/notify-user/custom-notification
Besides, I do not want a collapsed and expanded version of my notification as the example in the link has, just one full screen view.
TLDR; I want a notification that always engulfs the screen until the user presses a button on the notification to dismiss it. How can I further customize my full screen intent notification to truly take up the full screen? Ideally with a layout. If I must have a collapsed version of my notification, I don't want the user to ever see it, because I always want my notification to engulf the screen while it's showing.
There are existing apps such as AppBlock that have found a workaround to launching an activity-like thing from a foreground service that takes up the full screen, so what I am trying to do is possible even if the specific question I'm asking won't lead me to that result. Please suggest another way of accomplishing what I am after if what I am asking to do in my question is "impossible". What I generally want to do is certainly possible.

Android: Is there a way to disable notification bundling?

I have an app where the user can receive multiple notifications for things they need to do. The user has a choice of making some of these notifications persistent (which I achieve by calling NotificationCompat.Builder.setOngoing). At least on my version of Android which is Nougat, when more than three notifications are posted by my app they get bundled together into one notification, which makes all of them dismissible to the user in one swipe. This makes the previously persistent notifications no longer persistent. Is there a way to programmatically instruct Android not to bundle my notifications?
This is the code I use to build the notification and display it:
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(eventName + " " + notificationText)
.setDefaults(Notification.DEFAULT_ALL)
.setOnlyAlertOnce(true)
.setContentIntent(eventListPendingIntent);
if (goalInfo.goal.persistNotification) {
builder.setOngoing(true);
} else {
builder.setAutoCancel(true);
}
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(eventType.value(), builder.build());
Thanks, Nir
As per Google docs, notifications from the same app would be bundled automatically -
Note: If the same app sends four or more notifications and does not
specify a grouping, the system automatically groups them together.
So in your case, what you can do is , instead of system applying the default grouping, you can separate your notifications into two groups using a separate group key for the persistent notifications and one for the non-persistent ones.
Check the Google docs. The method Builder.setGroup() on NotificationBuilderCompat takes a string parameter which is the key.
There is a related method Builder.setGroupSummary which you should call on your Builder
Hope this is clear.

Add <fragment> in notification layout?

I'm developping a music player application for android and I'm stuck with a problem in the notification layout. It seems like I can't add any complicated element in it or it throws android.app.RemoteServiceException: Bad notification.
Problem is I wrote a player controller that is a Fragment. I can't find how to add the fragment by hand in code so I tried directly in XML layout but without success. I also had the problem with a custom ImageView that I wrote.
Am I really obliged to duplicate code ?
It does not look like you can add a fragment. You could see if MediaStyle fits your needs. In your notification builder you would add .setStyle(NotificationCompat.MediaStyle). Otherwise it looks like you would have to subclass Notification.Style or NotificationCompat.Style to create a custom layout. It also looks like for some options you can intercept the notification as it's being created. Check this out for more details.
Edit:
Given your time frame, and if you're willing to flex some on your layout, then I would just add buttons to the notification. Create a pending intent for each action you want to be able to do from your notification (play, pause, skip). By way of a code sample I've included an abbreviated version of how I put a dismiss button in my notifications.
Intent resultIntent = new Intent(context, AlarmScreen.class);
resultIntent.putExtra("Id",reminder.getId());
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
context,
reminder.getId()*2,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
Notification.Builder mBuilder =
new Notification.Builder(context)
.setStyle(new Notification.BigTextStyle()
.bigText(reminder.getDescription()))
.addAction(R.drawable.ic_stat_content_clear, "Dismiss", dismissPendingIntent)
.build();
In your case you should be able to replace the R.drawable.ic_stat_content_clear with an appropriate icon and maybe skip the text. You can just repeat .addAction() for each button you want. Notice also where I have reminder.getId()*2 in my pending intent declaration? I found that if I had the same number there for both of my buttons I got strange results, so one of my buttons has id*2 and the other has id*2+1.
As for how you handle the intents sent by the buttons, you'll have to create a BroadcastReceiver to receive them, and figure out where to go from there based on how you're implementing the rest of your logic.
That is not possible. Notification only able to use with RemoteView. RemoteView support some views only, and it do not support custom views or fragment.

Notification size when not showing first

I'm using local notification like clock alarm with buttons to control it. My problem is that the Notification view isn't wrapping my content. So after searching around I found out that there is a workaround to achieve this by setting the view after build.
Something like this:
Notification notification = mBuilder.build();
// add remote view after build for getting bigger notification size
notification.bigContentView = remoteViews;
This work unless the notification is not first and when it is not the top notification the buttons is not shown.
How can I make the notification wrap_content even when it is not the top on the list of notifications?
Set the priority Max for notification for showing big content view like below
new Notification.Builder(this)
.setContentTitle("Media Player")
.setContentIntent(mPendingIntentHomeSong)
.setSmallIcon(R.drawable.app_icon)
.setPriority(Notification.PRIORITY_MAX)
.setContent(mNotificationContentView)
.setStyle(new Notification.BigPictureStyle()).build();

How to correctly handle startForegrounds two notifications

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);
}

Categories

Resources