When I first built MyPOD way back in the the dark ages, I needed a download progressbar in my first notification – so I used a custom notification for it, and then by default for the rest of the notifications I needed in the app! Oops … It turns out that there is a bit of fragmentation around custom notifications over different SDK releases.
There were reports of the wrong colours on some devices (namely Samsung and ICS devices). After a bit (lot !!) of searching I found the highly informative:
http://stackoverflow.com/questions/4867338/custom-notification-layouts-and-text-colors
Basically the best way is to just use a Standard Android Notification and not try to customise it. Just supporting >=Gingerbread is also not an option for me, as this is about 30% of the total app userbase. If you do need custom (e.g. for my progress bar) then there are a few different things to cater for on different SDKs. An example is below and the table outlines the differences.
The moral of the story: Fragmentation
Thing can be a real nightmare real fast when we have to cater for fragmentation – things have to be tested so much more that it make development slow and tedious.
Android has really done a great job of hiding the immense fragmentation that we could be faced with, even though this rare case occurs, we have to admire the design-effort for such a generalised OS for so many devices.
| SDK | Issue | Solution |
| >=9 | Use Event styles | See Event Styles |
| <9 | No Event style present | See NotificationUpdater in the below custom example. |
| >=11 | Non standard background defaults | See also Custom Notification example. |
First you need an intent for the notifiction to fire when pressed:
Intent notificationIntent = new Intent(this, SelectFileActivity.class); notificationIntent.setAction(Globals.INTENT_DOWNLOAD_ALARM); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
A Standard Android Notification is created similar to below:
private Notification downloadedNotification(FileDb f,PendingIntent contentIntent){
Notification ntf = new Notification(
R.drawable.butt_tick_off_32,
"New files downloaded ...",
System.currentTimeMillis()
);
ntf.setLatestEventInfo(this, "Download complete", f.title, contentIntent);
return ntf;
}
Custom Notification Example
This example uses the custom class to set the colour and size of the TextView components.
There is still one problem though, on HoneyComb and ICS the background shows up as grey. I have just set it to black in the example, though the drawable should be in the Holo Theme somewhere.
private Notification getDlNotif(Context c,PendingIntent contentIntent,FileDb file) {
Notification notification = new Notification(
R.drawable.butt_dl_on_32,
"Downloading ...",
System.currentTimeMillis()
);
dlNotifContentView = new RemoteViews(getPackageName(), R.layout.download_notification);
dlNotifContentView.setImageViewResource(R.id.dln_img,R.drawable.butt_dl_on);
dlNotifContentView.setTextViewText(R.id.dln_dlfile,"Downloading ...");
dlNotifContentView.setTextViewText(R.id.dln_dlnumber, status);
dlNotifContentView.setProgressBar(R.id.dln_progress, 100, currentDownload.progress:0, false);
//set text colour and size for the title and text parts of the custom notification (if necessary ...)
if (getSDK()<10) {
NotificationUpdater.setTextTitleColourAndSize(this,dlNotifContentView,R.id.dln_dlfile);
NotificationUpdater.setTextColourAndSize(this,dlNotifContentView,R.id.dln_dlnumber);
}
//set background to black for >= HoneyComb(11)
if (getSDK()>=11) {
dlNotifContentView.setInt(R.id.dln_ctnr, "setBackgroundColor", Color.BLACK);
}
notification.contentView=dlNotifContentView;
notification.contentIntent = contentIntent;
return notification;
}
public static int getSDK() {
try {
return Integer.parseInt(Build.VERSION.SDK);
} catch (Throwable e) {
return 1;
}
}
For ginger bread and above we just need to use the relevant Event styles:
In the layout.xml( R.layout.download_notification in this case) …
/*For the title:*//*For the text:*/
NotificationUpdater
This class is needed for Android SDKs prior to Gingerbread (<9), it extracts the colours and sizes of the title and text in a standard notification, and saves them in statics, so we can use them in a custom one (see the above Custom Notification example). It is a modified version of the example given in the above stack overflow page.
import android.app.Notification;
import android.content.Context;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
public class NotificationUpdater {
private static Integer notificationTextColor = null;
private static Integer notificationTextTitleColor = null;
private static float notificationTextSize = 11;
private static float notificationTextTitleSize = 11;
private static final String COLOR_SEARCH_RECURSE_TIP = "TEXT";
private static final String COLOR_SEARCH_RECURSE_TITLE = "TITLE";
private static void recurseGroup(Context c,ViewGroup gp,DisplayMetrics metrics){
final int count = gp.getChildCount();
for (int i = 0; i < count; ++i) {
if (gp.getChildAt(i) instanceof TextView) {
final TextView text = (TextView) gp.getChildAt(i);
final String szText = text.getText().toString();
if (COLOR_SEARCH_RECURSE_TIP.equals(szText)) {
notificationTextColor = text.getTextColors().getDefaultColor();
notificationTextSize = text.getTextSize()/metrics.scaledDensity;
} else if (COLOR_SEARCH_RECURSE_TITLE.equals(szText)) {
notificationTextTitleColor = text.getTextColors().getDefaultColor();
notificationTextTitleSize = text.getTextSize()/metrics.scaledDensity;
}
} else if (gp.getChildAt(i) instanceof ViewGroup) {
recurseGroup(c,(ViewGroup) gp.getChildAt(i),metrics);
}
}
}
private static void extractColors(Context c)
{
try {
DisplayMetrics metrics = new DisplayMetrics();
WindowManager systemWM = (WindowManager)c.getSystemService(Context.WINDOW_SERVICE);
systemWM.getDefaultDisplay().getMetrics(metrics);
Notification ntf = new Notification();
ntf.setLatestEventInfo(c, COLOR_SEARCH_RECURSE_TITLE, COLOR_SEARCH_RECURSE_TIP, null);
LinearLayout group = new LinearLayout(c);
ViewGroup event = (ViewGroup) ntf.contentView.apply(c, group);
recurseGroup(c,event,metrics);
group.removeAllViews();
}
catch (Exception e) {
notificationTextColor = android.R.color.black;
notificationTextTitleColor = android.R.color.black;
}
}
public static void setTextColourAndSize(Context c, RemoteViews v,int i ) {
if (notificationTextColor==null) {
extractColors(c);
}
v.setTextColor(i, notificationTextColor);
v.setFloat(i, "setTextSize", notificationTextSize);
}
public static void setTextTitleColourAndSize(Context c, RemoteViews v,int i ) {
if (notificationTextColor==null) {
extractColors(c);
}
v.setTextColor(i, notificationTextTitleColor);
v.setFloat(i, "setTextSize", notificationTextTitleSize);
}
}






No comments yet!
You can be legendary and add one ...
All spam will be deleted - don't waste my time and yours. Fackbook profiles posted will be reported to FB as spam accounts
By submitting a comment you grant Sentinel Web Technologies a perpetual license to reproduce your words and name/web site in attribution. Inappropriate and irrelevant comments will be removed at an admin’s discretion. Your email is used for verification purposes only, it will never be shared.