Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Notification background in Android Lollipop is white. How can I change it?

I want to show a notification for a message in my app. In previous versions of Android everything is ok, but in Lollipop the notification background is white. I used this XML code for my notification layout in layout_message_notification.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_messageNotification"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_weight=".2"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent">

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:scaleType="fitCenter"
            android:src="@drawable/message_icon"/>

    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_weight=".8"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent">

        <TextView
            android:id="@+id/textView_notification_title"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:gravity="right|center_vertical"
            android:layout_margin="15dp"/>

    </LinearLayout>

</LinearLayout>

My notification in lollipop is shown like this: notification style in lollipop

How can I make the notification background dark or transparent, like in previous versions of Android?

like image 416
Mansour Avatar asked Jan 27 '15 11:01

Mansour


People also ask

How do I change the background color on my notifications?

call setColor -> the color to be used on the background. call setColorized -> the actual call to set the background color. set style to NotificationCompat. DecoratedMediaCustomViewStyle()

How to change notification icon Android?

1 Tap Notification Settings on the notification panel or tap the Settings app. 2 Tap Notifications. 3 Tap App icon badges.


1 Answers

This answer describes a hacky method of changing of notification background color.
Pay attention: this is an undocumented workaround; it is based on reflection and may be broken on custom firmwares; it is applicable to Android Lollipop and Marshmallow versions only; it will not work on Android N and higher versions. I would recommend to stick with the default color unless you have a serious reason to avoid it.

WHY
There is no legal way to set a background color for the custom notification. Google decided that notifications must be white or light gray depending on its priority according to Material Design. However, Google also made two exceptions to this rule:

  1. Notifications for older applications are displayed with black background;
  2. Notifications created with MediaStyle can be of ANY color.

As a result of the second exception, such limitation looks illogical and unreasoned, and that is the only possible excuse why you still want to use a custom color instead of the one that is recommended (or forced?) by Google.

WHAT'S INSIDE
Lets look into BaseStatusBar to see how this limitation is imposed. The only place where the background color for the notification is calculated is applyColorsAndBackgrounds method.
First branch of the if statement is for legacy applications. The only way to get here is to set the target SDK of your application below Build.VERSION_CODES.LOLLIPOP. The background will be turned black in this case.
We are interested in the entry.row.setTintColor statement. To reach it, several checks should be passed, including the one contained within isMediaNotification method. Here they are:

  1. The notification must contain both regular and big views.
  2. The top level layout in both views must have com.android.internal.R.id.status_bar_latest_event_content as its ID.
  3. The big layout must contain a widget with com.android.internal.R.id.media_actions as its ID.

HOW
The most problematic are IDs as long as they are declared in the internal resources and cannot be accessed from the application's layout XML.
The second problem is that the RemoteViews used in the notification is just an ID of the layout resource within the application and cannot be constructed in the code. As a result, we cannot add layouts with IDs required to pass all the checks mentioned above.

However, Google added the addView and removeAllViews methods into RemoteViews for their needs (they are used in the MediaStyle notification) and forgot to make them private.

So, the final idea is simple:

  • build the notification based on the internal layout defined by Google (to pass the 2nd check)
  • remove everything with removeAllViews
  • add our custom layout with addView
  • special case for big view: add the layout defined by Google which contains media_actions to invisible view inside of our custom layout (to pass the 3rd check)

Drawbacks:

  • inflating unused views (they are removed right after inflating)
  • complicated and deeper layout hierarchy

SOLUTION
Our custom big view must contain FrameLayout with android.R.id.empty as its ID. Actually, any ID may be used here, just make sure that you reference the same ID in code (see below).

// We need theese ids to use internal Android resources
int topId = Resources.getSystem().getIdentifier("status_bar_latest_event_content", "id", "android");
int topBigLayout = Resources.getSystem().getIdentifier("notification_template_material_big_media_narrow", "layout", "android");
int topSmallLayout = Resources.getSystem().getIdentifier("notification_template_material_media", "layout", "android");

RemoteViews viewSmall = ...; // Create our custom view here
RemoteViews viewBig = ...; // Create our custom big view here

// This is invisible inner view - to have media_actions in hierarchy
RemoteViews innerTopView = new RemoteViews("android", topBigLayout);
viewBig.addView(android.R.id.empty, innerTopView);

// This should be on top - we need status_bar_latest_event_content as top layout
RemoteViews topBigView = new RemoteViews("android", topBigLayout);
topBigView.removeAllViews(topId);
topBigView.addView(topId, viewBig);

// This should be on top - we need status_bar_latest_event_content as top layout
RemoteViews topSmallView = new RemoteViews("android", topSmallLayout);
topSmallView.removeAllViews(topId);
topSmallView.addView(topId, viewSmall);

Notification.Builder builder = new Notification.Builder(this);

builder.setSmallIcon(R.drawable.ic_notification)
        .setTicker("Some text")
        .setColor(0xff000000) // The desired color!
        .setContent(topSmallView);

Notification n = builder.build();
n.bigContentView = topBigView;

// Use our notification "n" here as usual

It is possible to use another layout instead of notification_template_material_big_media_narrow on the top level to manipulate the height of the big view. Search for appropriate one here among notification_template_xxx.xml files. But do not forget about putting media_actions into hierarchy.

like image 146
Stanislav Avatar answered Oct 10 '22 23:10

Stanislav