How to create a custom notification on Android

- Andrés Cruz

En español
How to create a custom notification on Android

In this post we will see how to create a personalized notification with Android using Android Studio as a software development environment.

What do we mean by personalized notification?

That we will use a view developed from scratch for this purpose; We will even use a series of buttons which can exercise their actions on the activity that creates said notification, services or Broadcast that we define.

Creating the custom notification

The itents in the data

The code for the view is a bit later in the post, but for now we'll walk you through the first steps of creating a notification in Android.

Intent intent = new Intent(getApplicationContext(), MusicService.class); noBundle.putInt("accion", 1);//This is the value I want to pass intent.putExtras(noBundle); PendingIntent pendingIntent = PendingIntent.getService(ListActivity.this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT); view.setOnClickPendingIntent(R.id.ibAccion, pendingIntent);

Let's explain the purpose of each code component presented above:

  • The Bundle It is generally used to pass data between components such as activities and fragments through numbers, texts or booleans.
  • The Intent is the component used to initiate communication between components such as starting an activity or service (more information in the official documentation).
  • The PendingIntent is an object that contains an intent; This PendingIntent object allows the NotificationManager to send the system the action to execute (such as opening an activity).

Very important flag PendingIntent.FLAG_UPDATE_CURRENT that together with:

<activity    android:name=".MainActivity"    android:configChanges="orientation|keyboardHidden|screenSize"    android:launchMode="singleTop"    android:screenOrientation="portrait"> ... </activity>

It indicates that the activity currently exists (by default the MainActivity is the first activity that started) and the android:launchMode="singleTop" and it is a way of indicating that the instance of the activity is unique, although there are other ways as you can consult in the following binding (in other words it means updating the instance of the activity that is currently running).

Defining custom view actions

Since there are three buttons, we need three different Intents and everything that this entails, so now we multiply this by three:

Intent intent = new Intent(getApplicationContext(), MusicService.class);
noBundle.putInt("accion", 1);//This is the value I want to pass
intent.putExtras(noBundle);
PendingIntent pendingIntent = PendingIntent.getService(ListActivity.this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.ibAccion, pendingIntent);

Bundle noBundle2 = new Bundle();
noBundle2.putInt("accion", 2);//This is the value I want to pass
Intent intent2 = new Intent(getApplicationContext(), ListActivity.class);
intent2.putExtras(noBundle2);
PendingIntent pendingIntent2 = PendingIntent.getActivity(ListActivity.this, 2, intent2, PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.ibQuitar, pendingIntent2);

Bundle noBundle3 = new Bundle();
noBundle3.putInt("accion", 3);//This is the value I want to pass
Intent intent3 = new Intent(getApplicationContext(), ListActivity.class);
intent3.putExtras(noBundle3);
PendingIntent pendingIntent3 = PendingIntent.getActivity(ListActivity.this, 3, intent3, PendingIntent.FLAG_UPDATE_CURRENT);
view.setOnClickPendingIntent(R.id.ibSiguiente, pendingIntent3);

Launching the custom notification

Now we can create our notification; first, the notification manager (NotificationManager) which, as its name indicates, and through an instance of this class we can launch the notification with the NotificationCompat.Build, we can establish the notification properties and create the notification itself; for example, we indicate the title, subtitle, the icon and the PendingIntent whose action will be exercised when the user clicks on the notification:

NotificationManager nManager;
NotificationCompat.Builder nBuilder;
RemoteViews remoteView;

PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
        new Intent(this, ListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);

nBuilder = new NotificationCompat.Builder(this)
        .setContentTitle(getString(R.string.app_name))
        .setTicker(getString(R.string.app_name))
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentIntent(contentIntent)
        .setOngoing(false)
        .setAutoCancel(false);

As we can see, when creating the notification we establish several parameters such as the content (title), icon and the same Intent that we defined previously.

Now we need to specify which is the view in question (the one that has the design that we created with the three buttons), we do this through a RemoteViews:

remoteView = new RemoteViews(getPackageName(), R.layout.notification_layout);
remoteView.setImageViewResource(R.id.image, R.mipmap.ic_launcher);
remoteView.setTextViewText(R.id.title, "Título");
remoteView.setTextViewText(R.id.text,"Nombre");

As we can see in the previous code, we access each of its components and establish a value that for the purposes of this tutorial are fixed.

In our case the view has the following content:

<?xml version="1.0" encoding="UTF-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="#333333"
    android:orientation="vertical"
    android:weightSum="1">

    <LinearLayout
        android:id="@+id/right"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/imagenotileft"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:background="@mipmap/ic_launcher" />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:orientation="vertical">

            <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:layout_marginRight="5dp"
                android:layout_marginTop="9dp"
                android:textColor="#FFFFFF"
                android:textSize="16sp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/title"
                android:layout_marginLeft="5dp"
                android:layout_marginRight="5dp"
                android:textColor="#EEEEEE"
                android:textSize="14sp" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:orientation="horizontal">

            <ImageButton
                android:id="@+id/ibAtras"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_margin="0dp"
                android:background="@NULL"
                android:gravity="center_horizontal|center_vertical"
                android:padding="0dp"
                android:src="@drawable/ic_action_av_skip_previous" />

            <ImageButton
                android:id="@+id/ibAccion"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_margin="0dp"
                android:background="@NULL"
                android:gravity="center_horizontal|center_vertical"
                android:padding="0dp"
                android:src="@drawable/ic_action_ic_play_pause" />

            <ImageButton
                android:id="@+id/ibSiguiente"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_margin="0dp"
                android:background="@NULL"
                android:gravity="center_horizontal|center_vertical"
                android:padding="0dp"
                android:src="@drawable/ic_action_av_skip_next" />

            <Button
                android:id="@+id/ibQuitar"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_margin="0dp"
                android:background="@NULL"
                android:gravity="center_horizontal|center_vertical"
                android:padding="0dp"
                android:text="X"
                android:textColor="#444444"
                android:textSize="16sp" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>
Notificación Personalizada

Finally we set the previous view and launch the notification:

        setListeners(remoteView);
        nBuilder.setContent(remoteView);

        nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        nManager.notify(2, nBuilder.build());

Replicate notifications on Android

So far we have seen how to create a notification with a custom layout and how to interact with the elements that we define in this layout such as Buttons or ImageView, etc; in this second part of this entry we will see how to create notifications that can be replicated; This is an action widely used in messaging applications such as Google Hangout or WhatsApp itself on Android.

Compatibility between notifications

Notifications have a great backwards compatibility using the NotificationCompat.Builder class and we can use many options that have from priority to styles but we must keep in mind what functionalities we use since some specific functions are provided only for higher versions of Android than the 4.1.

Creating the means for passing data between components: PendingIntent

The first thing we must do is create a PendingIntent and associate the Intent that is the means used to pass data from a component; these components can not only be Activities or Fragments, they can also be others such as Broadcast to perform updates in the background without the need to call the activity; although for this we must use Android N from now on; In order not to overextend this entry, we will go with the case in which the activity is invoked.

The PendingIntent is the existing mechanism that we have to pass data between different components such as activities, broadcasts or services that embeds within it the data that we want to pass to these components (in case you want to pass data):

RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
       .setLabel(replyLabel)
       .build();

Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.setAction(KEY_TEXT_REPLY);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent replyPendingIntent =
       stackBuilder.getPendingIntent(
               0,
               PendingIntent.FLAG_UPDATE_CURRENT
       );

The setAction method allows you to associate the name of the data to be passed, which in this case will be the text that the user provides in the reply field and with this name we access the text that the user entered in the onCreate of our activity:

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   Intent intent = getIntent();

   if (KEY_TEXT_REPLY.equals(intent.getAction())) {

       Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
       if (remoteInput != NULL) {
           Log.i("REPLICA", "" + remoteInput.getCharSequence(KEY_TEXT_REPLY));
       }

   }
   replyNotification();
}

With the RemoteInput method we indicate that we will create a mechanism for passing data inside the PendingIntent; In addition, we associate the label or text that will appear in the reply field.

Creating the replica notification

We associate the PendingIntent that we created earlier:

NotificationCompat.Action action =
       new NotificationCompat.Action.Builder(R.mipmap.ic_launcher,
               "Replicar", replyPendingIntent)
               .addRemoteInput(remoteInput)
               .build();

Creating the replica notification

We create the notification by establishing its content: representative icon, title, content and the action that we configured in the previous block:

NotificationCompat.Builder newMessageNotification =
       new NotificationCompat.Builder(MainActivity.this)
               .setSmallIcon(R.mipmap.ic_launcher)
               .setContentTitle("My notification")
               .setContentText("Hello World!")
               .addAction(action);

Finally we launch the notification along with the actions we configured in the previous steps through the build() method:

NotificationManagerCompat notificationManager =
       NotificationManagerCompat.from(MainActivity.this);
notificationManager.notify(NOTIFICATION_ID, newMessageNotification.build());

The complete method looks like:

    public void replyNotification() {
        RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY)
                .setLabel(replyLabel)
                .build();

        Intent resultIntent = new Intent(this, MainActivity.class);
        resultIntent.setAction(KEY_TEXT_REPLY);
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        stackBuilder.addParentStack(MainActivity.class);
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent replyPendingIntent =
                stackBuilder.getPendingIntent(
                        0,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );

        NotificationCompat.Action action =
                new NotificationCompat.Action.Builder(R.mipmap.ic_launcher,
                        "Replicar", replyPendingIntent)
                        .addRemoteInput(remoteInput)
                        .build();


        NotificationCompat.Builder newMessageNotification =
                new NotificationCompat.Builder(MainActivity.this)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setContentTitle("My notification")
                        .setContentText("Hello World!")
                        .addAction(action);

        NotificationManagerCompat notificationManager =
                NotificationManagerCompat.from(MainActivity.this);
        notificationManager.notify(NOTIFICATION_ID, newMessageNotification.build());
    }

Finally the result is the following:

Notificación de Réplica en android

Reference Links:

Andrés Cruz

Develop with Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz In Udemy

I agree to receive announcements of interest about this Blog.