Custom notification layouts and text colors
Here is solution for any SDK version using only resources.
res/values/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="NotificationTitle">
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
<item name="android:textStyle">bold</item>
</style>
<style name="NotificationText">
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
</style>
</resources>
res/values-v9/styles.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="NotificationText" parent="android:TextAppearance.StatusBar.EventContent" />
<style name="NotificationTitle" parent="android:TextAppearance.StatusBar.EventContent.Title" />
</resources>
res/layout/my_notification.xml
...
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title"
style="@style/NotificationTitle"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="text"
style="@style/NotificationText"
/>
...
P.S: Hard coded values are used for 2.2-. So problems can occur with some rare old custom firmwares.
The solution is to use built-in styles. The style you need is called TextAppearance.StatusBar.EventContent
in Android 2.3 and Android 4.x. In Android 5.x material notifications use several other styles: TextAppearance.Material.Notification
, TextAppearance.Material.Notification.Title
, and TextAppearance.Material.Notification.Line2
. Just set the appropriate text appearance for the text view, and you will get the necessary colors.
If you are interested how I have arrived at this solution, here's my trail of breadcrumbs. The code excerpts are taken from Android 2.3.
When you use
Notification
and set the text by using built-in means, the following line creates the layout:RemoteViews contentView = new RemoteViews(context.getPackageName(), com.android.internal.R.layout.status_bar_latest_event_content);
The mentioned layout contains the following
View
which is responsible for viewing notification text:<TextView android:id="@+id/text" android:textAppearance="@style/TextAppearance.StatusBar.EventContent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:singleLine="true" android:ellipsize="marquee" android:fadingEdge="horizontal" android:paddingLeft="4dp" />
So the conclusion is that the needed style is
TextAppearance.StatusBar.EventContent
, which definition looks like this:<style name="TextAppearance.StatusBar.EventContent"> <item name="android:textColor">#ff6b6b6b</item> </style>
You should note here that this style doesn't actually reference any of the built-in colors, so the safest way is to apply this style instead of some built-in color.
One more thing: before Android 2.3 (API Level 9), there were neither styles, nor colors, there were only hard-coded values. If you happen to have to support such old versions for some reason, see the answer by Gaks .
For 2.3+ (From Android documentation):
Use the style android:TextAppearance.StatusBar.EventContent.Title
for the primary text.
Use the style android:TextAppearance.StatusBar.EventContent
for the secondary text.
For 2.2-, do what Gaks suggested in another answer to this thread.
If you want to compile against 2.2 and support 2.3+, and support all the variety of devices out there, Gaks' solution is the only one I know.
BTW, what Google suggested about using the value ?android:attr/textColorPrimary
for 2.2-, isn't working. Just try it using the emulator. Gaks' way is the only way.
More resources: This and this do not work.
Solution by Malcolm works fine with API>=9. Here's the solution for older API:
The trick is to create the standard notification object and then traverse the default contentView
created by Notification.setLatestEventInfo(...)
. When you find the right TextView, just get the tv.getTextColors().getDefaultColor()
.
Here's the code that extracts the default text color and text size (in scaled density pixels - sp).
private Integer notification_text_color = null;
private float notification_text_size = 11;
private final String COLOR_SEARCH_RECURSE_TIP = "SOME_SAMPLE_TEXT";
private boolean recurseGroup(ViewGroup gp)
{
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))
{
notification_text_color = text.getTextColors().getDefaultColor();
notification_text_size = text.getTextSize();
DisplayMetrics metrics = new DisplayMetrics();
WindowManager systemWM = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
systemWM.getDefaultDisplay().getMetrics(metrics);
notification_text_size /= metrics.scaledDensity;
return true;
}
}
else if (gp.getChildAt(i) instanceof ViewGroup)
return recurseGroup((ViewGroup) gp.getChildAt(i));
}
return false;
}
private void extractColors()
{
if (notification_text_color != null)
return;
try
{
Notification ntf = new Notification();
ntf.setLatestEventInfo(this, COLOR_SEARCH_RECURSE_TIP, "Utest", null);
LinearLayout group = new LinearLayout(this);
ViewGroup event = (ViewGroup) ntf.contentView.apply(this, group);
recurseGroup(event);
group.removeAllViews();
}
catch (Exception e)
{
notification_text_color = android.R.color.black;
}
}
Call extractColors
ie. in onCreate() of your service. Then when you're creating the custom notification, the color and text size you want are in notification_text_color
and notification_text_size
:
Notification notification = new Notification();
RemoteViews notification_view = new RemoteViews(getPackageName(), R.layout.notification);
notification_view.setTextColor(R.id.label, notification_text_color);
notification_view.setFloat(R.id.label, "setTextSize", notification_text_size);