Integrating Bubbl Notifications with existing Notifications List on Android

Bubbl provides the ability, out-of-the-box, to render a prebuilt Activity that display the device user with the notifications sent to their device. For more information on this see here.

Many apps will already have the ability to display notifications and messages as a list with the current app design. The Bubbl Plugin provides an additional out-of-the-box method to obtain the Bubbl notifications that have been sent to the device, thus allowing these to be integrated into a single combined list as the app developer requires.

The following example code uses an Activity named `YourBubblActivity that has a custom ArrayAdapter for a POJO named YourNotification. The base class of YourNotification, before Bubbl's Notification is introduced, looks like the following; your class may be structured differently.

import java.util.Date;

public class YourNotification {
    String title;
    String message;
    Date deliveryDate;
    Date expirtyDate;
  
    public YourNotification() {
      // Empty constructor
    }

    public YourNotification(String title, String message, Date deliveryDate) {
        this.title = title;
        this.message = message;
        this.deliveryDate = deliveryDate;
        this.expirtyDate = expirtyDate;
    }

    // Getters and setters go here ...
}

POJO (Plain Old Java Object)

The Bubbl RestBubblDeliveredNotification class provides the data that can be used within the app. The available properties are:

  • id -> the Bubbl Platform Id of the Notification (always available)
  • type -> the Type of Notification (message, image, audio, video or survey)
  • title -> the Title used when the notification is display (always available)
  • message -> text to be displayed on the notification (this is optional for all but Message notifications)
  • url -> the URL of the resource (only for image, audio and video notification types)
  • ctaLabel and ctaDeepLink -> the text for the Call to Action button on the notification, if a CTA button is included on the notification.
  • notificationDeliveryDate -> the date the notification was delivered the device
  • expiryDate -> the date the notification will no longer be available from

📘

Survey notification

When a survey has been submitted by a user it will no longer be available in the list of notifications provided by the Bubbl Plugin

Activity

The Activity must implement the provided BubblDeliveredNotificationsCallback interface. This has a single method that must be implemented.

public void deliveredNotificationsCallback(List<RestBubblDeliveredNotification> deliveredNotificationList) {
  // Your bespoke code goes here
}

The onCreate method of the Activity should invoke the Bubbl Plugin to load the data as follows:

        BubblDeliveredNotifications bubblDeliveredNotifications = new BubblDeliveredNotifications();
        bubblDeliveredNotifications.load(this);

The load method will call the deliveredNotificationsCallback method upon completion and at that point the Bubbl Notification Data should be migrated to your notification objects, as required by custom ArrayAdapter. This can be done within the deliveredNotificationsCallback method as follows.

        for (RestBubblDeliveredNotification bubblNotification : deliveredNotificationList) {
            dataModels.add(
                new YourNotification(
                    bubblNotification.getTitle(),
                    bubblNotification.getMessage(),
                    bubblNotification.getNotificationDeliveryDate(),
                    bubblNotification.getExpiryDate()
                )
            );
        }

Full example code

POJO using all Bubbl Notification properties

import java.util.Date;

public class YourNotification {
    String bubblNotificationType;
    Integer bubblNotificationId;
    String title;
    String message;
    String bubblNotificationUrl;
    String bubblNotificationCtaLabel;
    String bubblNotificationCtaLink;
    Date deliveryDate;
    Date expirtyDate;

    public YourNotification(String bubblNotificationType, Integer bubblNotificationId, String title, String message, Date deliveryDate) {
        this.bubblNotificationType = bubblNotificationType;
        this.bubblNotificationId = bubblNotificationId;
        this.title = title;
        this.message = message;
        this.deliveryDate = deliveryDate;
    }

    public YourNotification(String bubblNotificationType, Integer bubblNotificationId, String title, String message, String bubblNotificationUrl, Date deliveryDate) {
        this.bubblNotificationType = bubblNotificationType;
        this.bubblNotificationId = bubblNotificationId;
        this.title = title;
        this.message = message;
        this.bubblNotificationUrl = bubblNotificationUrl;
        this.deliveryDate = deliveryDate;
    }

    public YourNotification(String bubblNotificationType, Integer bubblNotificationId, String title, String message, String bubblNotificationUrl, Date deliveryDate, String bubblNotificationCtaLabel, String bubblNotificationCtaLink, Date expirtyDate) {
        this.bubblNotificationType = bubblNotificationType;
        this.bubblNotificationId = bubblNotificationId;
        this.title = title;
        this.message = message;
        this.bubblNotificationUrl = bubblNotificationUrl;
        this.deliveryDate = deliveryDate;
        this.bubblNotificationCtaLabel = bubblNotificationCtaLabel;
        this.bubblNotificationCtaLink = bubblNotificationCtaLink;
        this.expirtyDate = expirtyDate;
    }

    public String getBubblNotificationType() {
        return bubblNotificationType;
    }

    public void setBubblNotificationType(String bubblNotificationType) {
        this.bubblNotificationType = bubblNotificationType;
    }

    public Integer getBubblNotificationId() {
        return bubblNotificationId;
    }

    public void setBubblNotificationId(Integer bubblNotificationId) {
        this.bubblNotificationId = bubblNotificationId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getBubblNotificationUrl() {
        return bubblNotificationUrl;
    }

    public void setBubblNotificationUrl(String bubblNotificationUrl) {
        this.bubblNotificationUrl = bubblNotificationUrl;
    }

    public String getBubblNotificationCtaLabel() {
        return bubblNotificationCtaLabel;
    }

    public void setBubblNotificationCtaLabel(String bubblNotificationCtaLabel) {
        this.bubblNotificationCtaLabel = bubblNotificationCtaLabel;
    }

    public String getBubblNotificationCtaLink() {
        return bubblNotificationCtaLink;
    }

    public void setBubblNotificationCtaLink(String bubblNotificationCtaLink) {
        this.bubblNotificationCtaLink = bubblNotificationCtaLink;
    }

    public Date getDeliveryDate() {
        return deliveryDate;
    }

    public void setDeliveryDate(Date deliveryDate) {
        this.deliveryDate = deliveryDate;
    }

    public Date getExpirtyDate() {
        return expirtyDate;
    }

    public void setExpirtyDate(Date expirtyDate) {
        this.expirtyDate = expirtyDate;
    }
}

Custom Adapter

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;

import tech.bubbl.showcase.android.R;

public class YourNotificationCustomAdapter extends ArrayAdapter<YourNotification> implements View.OnClickListener{
    static final DateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyy hh:mm");
    private ArrayList<YourNotification> dataSet;
    Context mContext;

    // View lookup cache
    private static class ViewHolder {
        TextView txtTitle;
        TextView txtDeliveredOnDate;
        TextView txtExpiryDate;
    }

    public YourNotificationCustomAdapter(ArrayList<YourNotification> data, Context context) {
        super(context, R.layout.activity_yourbubbl_listitem, data);
        this.dataSet = data;
        this.mContext=context;
    }

    @Override
    public void onClick(View v) {
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Get the data item for this position
        YourNotification dataModel = getItem(position);
        // Check if an existing view is being reused, otherwise inflate the view
        ViewHolder viewHolder; // view lookup cache stored in tag

        final View result;

        if (convertView == null) {

            viewHolder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(R.layout.activity_yourbubbl_listitem, parent, false);
            viewHolder.txtTitle = (TextView) convertView.findViewById(R.id.notification_title);
            viewHolder.txtDeliveredOnDate = (TextView) convertView.findViewById(R.id.notification_delivered_date);
            viewHolder.txtExpiryDate = (TextView) convertView.findViewById(R.id.notification_expiry_date);

            result=convertView;

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
            result=convertView;
        }

        viewHolder.txtTitle.setText(dataModel.getTitle());
        viewHolder.txtDeliveredOnDate.setText(DATE_FORMAT.format(dataModel.getDeliveryDate()));
        viewHolder.txtExpiryDate.setText(DATE_FORMAT.format(dataModel.getExpirtyDate()));

        // Return the completed view to render on screen
        return convertView;
    }
}

Custom Views

Simple List View

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ListActivity" >

    <ListView
        android:id="@+id/list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />

</RelativeLayout>

Simple List View Item

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="16dp"
    android:paddingRight="16dp" >
    <TextView
        android:id="@+id/notification_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/notification_delivered_date_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/notification_title"
        android:layout_alignParentLeft="true"
        android:text="Delivered on:"
        android:layout_toLeftOf="@+id/notification_delivered_date"  />
    <TextView
        android:id="@+id/notification_delivered_date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/notification_title"
        android:layout_alignParentRight="true" />
    <TextView
        android:id="@+id/notification_expiry_date_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/notification_delivered_date_label"
        android:layout_alignParentLeft="true"
        android:text="Expires:"
        android:layout_toLeftOf="@+id/notification_expiry_date"  />
    <TextView
        android:id="@+id/notification_expiry_date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/notification_delivered_date_label"
        android:layout_alignParentRight="true" />
</RelativeLayout>

Activity

import android.os.Bundle;
import android.widget.ListView;

import androidx.appcompat.app.AppCompatActivity;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import tech.bubbl.sdk.RestBubblDeliveredNotification;
import tech.bubbl.sdk.bubblpublic.BubblDeliveredNotificationsCallback;
import tech.bubbl.sdk.bubblpublic.BubblDeliveredNotifications;
import tech.bubbl.showcase.android.R;

public class YourBubblActivity extends AppCompatActivity implements BubblDeliveredNotificationsCallback {
    ArrayList<YourNotification> dataModels;
    ListView listView;
    private static YourNotificationCustomAdapter adapter;

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

        listView = findViewById(R.id.list);

        dataModels = new ArrayList<>();
        BubblDeliveredNotifications bubblDeliveredNotifications = new BubblDeliveredNotifications();
        bubblDeliveredNotifications.load(this);

        adapter = new YourNotificationCustomAdapter(dataModels, getApplicationContext());

        listView.setAdapter(adapter);

        listView.setOnItemClickListener((parent, view, position, id) -> {
            YourNotification dataModel = dataModels.get(position);

            bubblDeliveredNotifications.open(
                this,
                dataModel.getBubblNotificationType(),
                dataModel.getBubblNotificationId(),
                dataModel.getTitle(),
                dataModel.getMessage(),
                dataModel.getBubblNotificationUrl(),
                dataModel.getBubblNotificationCtaLabel(),
                dataModel.getBubblNotificationCtaLink()
            );
        });
    }

    @Override
    /**
     * The `dataModels` List should already contain non-Bubbl Notifications, or have them added within this code block
     */
    public void deliveredNotificationsCallback(List<RestBubblDeliveredNotification> deliveredNotificationList) {
        for (RestBubblDeliveredNotification bubblNotification : deliveredNotificationList) {
            dataModels.add(
                new YourNotification(
                    bubblNotification.getType(),
                    bubblNotification.getId(),
                    bubblNotification.getTitle(),
                    bubblNotification.getMessage(),
                    bubblNotification.getUrl(),
                    bubblNotification.getNotificationDeliveryDate(),
                    bubblNotification.getCtaLabel(),
                    bubblNotification.getCtaDeepLink(),
                    bubblNotification.getExpiryDate()
                )
            );
        }

        // Sort the notification with most recently delivered first
        dataModels.sort(new Comparator<YourNotification>() {
            @Override
            public int compare(YourNotification notification1, YourNotification notification2) {
                return notification2.getDeliveryDate().compareTo(notification1.deliveryDate);
            }
        });

        adapter = new YourNotificationCustomAdapter(dataModels, getApplicationContext());

        listView.setAdapter(adapter);
    }
}