Carousel Push

Carousel Push functionality allows you to show your notification with a slideshow.

Requirements

  • Android SDK 2.0.0+

Before you start, you need to define your receiver in your manifest file.

Defining Custom Receiver

<receiver android:name=".MyReceiver"  
  android:exported="false">   <!-- change NotificationReceiver to .MyReceiver -->
 <intent-filter> 
 ... 
	<action android:name="com.dengage.push.intent.ITEM_CLICK" /> <!-- add this line-->  
	<action android:name="com.dengage.push.intent.CAROUSEL_ITEM_CLICK" /><!-- add this line-->   
 </intent-filter>
 </receiver>

Preparing Custom Layouts

The SDK uses custom layout for the functionality. It means you need to set your layout first in your res folder. At the same time, We prepared 2 pre-build layouts that you can easily use;

  • Landscape
  • Portrait

To use them, Please add den_carousel_landscape.xml or den_carousel_portrait.xml file to your layouts directory.

den_carousel_landscape.xml Note: You will need to change drawable items with yours.

<?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="wrap_content">

    <include
        android:id="@+id/den_carousel_collapsed"
        layout="@layout/den_carousel_collapsed"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>


    <FrameLayout
        android:id="@+id/den_carousel_frame"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/den_carousel_collapsed"
        android:layout_gravity="center"
        android:paddingLeft="16dp"
        android:paddingRight="16dp">

        <ImageView
            android:id="@+id/den_carousel_landscape_image"
            android:layout_width="match_parent"
            android:layout_height="160dp"
            android:scaleType="centerCrop"
            android:layout_gravity="center"
            />

        <ImageView
            android:id="@+id/den_carousel_left_image"
            android:layout_width="44dp"
            android:layout_height="44dp"
            android:src="@drawable/ic_carousal_left_arrow"
            android:layout_gravity="start|center_vertical"
            android:scaleType="fitXY"
            android:layout_marginStart="5dp" />

        <ImageView
            android:id="@+id/den_carousel_right_image"
            android:layout_width="44dp"
            android:layout_height="44dp"
            android:src="@drawable/ic_carousal_right_icon"
            android:layout_gravity="end|center_vertical"
            android:scaleType="fitXY"
            android:layout_marginEnd="5dp" />


    </FrameLayout>

    <LinearLayout android:id="@+id/den_carousel_item_title_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_below="@id/den_carousel_frame"
        android:layout_marginTop="5dp"
        >
        <TextView
            android:id="@+id/den_carousel_item_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Item Title"
            />
    </LinearLayout>

    <LinearLayout android:id="@+id/den_carousel_item_description_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_below="@id/den_carousel_item_title_container"
        >
        <TextView
            android:id="@+id/den_carousel_item_description"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Item Description" />
    </LinearLayout>     
</RelativeLayout>

den_carousel_portrait.xml Note: You will need to change drawable items with yours.

<?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="320dp">

    <include
        android:id="@+id/den_carousel_collapsed"
        layout="@layout/den_carousel_collapsed"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <FrameLayout
        android:id="@+id/den_carousel_body_portrait"
        android:layout_width="596dp"
        android:layout_height="wrap_content"
        android:layout_below="@id/den_carousel_collapsed"
        android:layout_gravity="center"
        android:layout_marginBottom="8dp"
        android:paddingLeft="16dp"
        android:paddingRight="16dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center">

            <RelativeLayout
                android:id="@+id/den_carousel_left_container"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toStartOf="@+id/den_carousel_portrait_current_container"
                android:layout_toLeftOf="@+id/den_carousel_portrait_current_container">

                <ImageView
                    android:id="@+id/den_carousel_portrait_left_image"
                    android:layout_width="192dp"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:scaleType="centerCrop" />

                <RelativeLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignBottom="@+id/den_carousel_portrait_left_image"
                    android:layout_alignStart="@+id/den_carousel_portrait_left_image"
                    android:layout_alignLeft="@+id/den_carousel_portrait_left_image"
                    android:layout_alignEnd="@+id/den_carousel_portrait_left_image"
                    android:layout_alignRight="@+id/den_carousel_portrait_left_image"
                    android:layout_alignTop="@+id/den_carousel_portrait_left_image"
                    android:background="#BFffffff" />
            </RelativeLayout>

            <RelativeLayout
                android:id="@+id/den_carousel_right_container"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toEndOf="@+id/den_carousel_portrait_current_container"
                android:layout_toRightOf="@+id/den_carousel_portrait_current_container">

                <ImageView
                    android:id="@+id/den_carousel_portrait_right_image"
                    android:layout_width="192dp"
                    android:layout_height="192dp"
                    android:layout_centerInParent="true"
                    android:scaleType="centerCrop" />

                <RelativeLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignBottom="@+id/den_carousel_portrait_right_image"
                    android:layout_alignStart="@+id/den_carousel_portrait_right_image"
                    android:layout_alignLeft="@+id/den_carousel_portrait_right_image"
                    android:layout_alignEnd="@+id/den_carousel_portrait_right_image"
                    android:layout_alignRight="@+id/den_carousel_portrait_right_image"
                    android:layout_alignTop="@+id/den_carousel_portrait_right_image"
                    android:background="#B0ffffff" />

            </RelativeLayout>

            <RelativeLayout
                android:id="@+id/den_carousel_portrait_current_container"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true">

                <ImageView
                    android:id="@+id/den_carousel_portrait_current_image"
                    android:layout_width="212dp"
                    android:layout_height="192dp"
                    android:paddingLeft="10dp"
                    android:paddingRight="10dp"
                    android:cropToPadding="true"
                    android:scaleType="centerCrop" />


            </RelativeLayout>

        </RelativeLayout>

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp">

            <ImageView
                android:id="@+id/den_carousel_left_arrow"
                android:layout_width="44dp"
                android:layout_height="44dp"
                android:src="@drawable/ic_carousal_left_arrow"
                android:layout_gravity="start|center_vertical"
                android:scaleType="fitXY" />

            <ImageView
                android:id="@+id/den_carousel_right_arrow"
                android:layout_width="44dp"
                android:layout_height="44dp"
                android:src="@drawable/ic_carousal_right_icon"
                android:layout_gravity="end|center_vertical"
                android:scaleType="fitXY" />

        </FrameLayout>

    </FrameLayout>

    <LinearLayout android:id="@+id/den_carousel_item_title_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_below="@id/den_carousel_body_portrait"
        >
        <TextView
            android:id="@+id/den_carousel_item_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Item Title"
            />
    </LinearLayout>

    <LinearLayout android:id="@+id/den_carousel_item_description_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_below="@id/den_carousel_item_title_container"
        >
        <TextView
            android:id="@+id/den_carousel_item_description"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="Item Description" />
    </LinearLayout>
</RelativeLayout>

The above layout includes den_carousel_collapsed.xml file;

den_carousel_collapsed.xml Note: You will need to change drawable items with yours.

<?xml version="1.0" encoding="utf-8"?>
<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="wrap_content"
    android:paddingTop="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp">

    <ImageView
        android:id="@+id/den_carousel_image"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_gravity="top|end"
        android:layout_marginLeft="12dp"
        android:layout_marginStart="12dp"
        android:scaleType="centerCrop"
        android:src="@drawable/ic_launcher_foreground" /> <!-- Your App Icon -->

    <TextView
        android:id="@+id/den_carousel_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toStartOf="@+id/den_carousel_image"
        android:layout_toLeftOf="@id/den_carousel_image"
        android:text="Remote Title"
        android:textSize="15dp"
        android:textColor="@color/colorPrimary"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/den_carousel_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/den_carousel_title"
        android:layout_alignStart="@+id/den_carousel_title"
        android:layout_alignLeft="@+id/den_carousel_title"
        android:layout_alignEnd="@+id/den_carousel_title"
        android:layout_alignRight="@+id/den_carousel_title"
        android:layout_toLeftOf="@id/den_carousel_image"
        android:ellipsize="end"
        android:lineSpacingMultiplier="1.2"
        android:maxLines="1"
        android:text="Remote message"
        android:textSize="14dp"
        android:textColor="@color/colorPrimary"
        android:layout_marginBottom="16dp"/>

</RelativeLayout>

Please note that you can always edit these layouts or create new one.

Building Notification

To use a custom layout for the notification requires building a message by the developer with the layout.

First, please create your receiver class extends from NotificationReceiver and override the methods below;

  • onRender
  • onReRender
class PushNotificationReceiver : NotificationReceiver() {
    override fun onCarouselRender(context: Context, intent: Intent?, message: Message?) {
        // build carousel message with a custom layout. In this case, we will use dengage_carousel_landscape.xml and dengage_carousel_portrait.xml files.
    }
    override fun onCarouselReRender(context: Context, intent: Intent?, message: Message?) {
        // Re-build carousel message with a custom layout to slide item next/prev. 
    }
}

Building Landscape Carousel

Copy the codes below to your receiver class.

class PushNotificationReceiver : NotificationReceiver() {

    override fun onCarouselRender(context: Context, intent: Intent?, message: Message?) {
        super.onCarouselRender(context, intent, message)

        val items = message?.carouselContent
        if (items.isNullOrEmpty() || intent == null) return
        val size = items.size
        val current = 0
        val left = (current - 1 + size) % size
        val right = (current + 1) % size

        val itemTitle = items[current].title
        val itemDesc = items[current].description

        // set intents (right button, left button, item click)
        val itemIntent = getItemClickIntent(intent.extras, context.packageName)
        val leftIntent = getLeftItemIntent(intent.extras, context.packageName)
        val rightIntent = getRightItemIntent(intent.extras, context.packageName)
        val deleteIntent = getDeleteIntent(intent.extras, context.packageName)
        val contentIntent = getContentIntent(intent.extras, context.packageName)
        val carouseItemIntent = PendingIntent.getBroadcast(
            context, 0,
            itemIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val carouselLeftIntent = PendingIntent.getBroadcast(
            context, 1,
            leftIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val carouselRightIntent = PendingIntent.getBroadcast(
            context, 2,
            rightIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val deletePendingIntent = PendingIntent.getBroadcast(
            context, 4,
            deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val contentPendingIntent = PendingIntent.getBroadcast(
            context, 5,
            contentIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )

        // set views for the layout
        val collapsedView = RemoteViews(
            context.packageName,
            R.layout.den_carousel_collapsed
        )
        collapsedView.setTextViewText(R.id.den_carousel_title, message.title)
        collapsedView.setTextViewText(R.id.den_carousel_message, message.message)
        val carouselView = RemoteViews(
            context.packageName,
            R.layout.den_carousel_landscape
        )
        carouselView.setTextViewText(R.id.den_carousel_title, message.title)
        carouselView.setTextViewText(R.id.den_carousel_message, message.message)
        carouselView.setTextViewText(R.id.den_carousel_item_title, itemTitle)
        carouselView.setTextViewText(R.id.den_carousel_item_description, itemDesc)

        carouselView.setOnClickPendingIntent(R.id.den_carousel_left_arrow, carouselLeftIntent)
        carouselView.setOnClickPendingIntent(
            R.id.den_carousel_landscape_current_image,
            carouseItemIntent
        )
        carouselView.setOnClickPendingIntent(R.id.den_carousel_item_title, carouseItemIntent)
        carouselView.setOnClickPendingIntent(R.id.den_carousel_item_description, carouseItemIntent)
        carouselView.setOnClickPendingIntent(R.id.den_carousel_right_arrow, carouselRightIntent)

        val channelId = createNotificationChannel(context, message)

        // set views for the notification
        val notification = NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setCustomContentView(collapsedView)
            .setCustomBigContentView(carouselView)
            .setContentIntent(contentPendingIntent)
            .setDeleteIntent(deletePendingIntent)
            .build()


        // --------- Behavior-1 ---------
        /*Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_landscape_left_image,
            items[left]
        )
        Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_landscape_current_image,
            items[current]
        )
        Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_landscape_right_image,
            items[right]
        )

        // show message
        val notificationManager = NotificationManagerCompat.from(context)
        notificationManager.notify(
            message.messageSource,
            message.messageId,
            notification
        )*/
        // --------- Behavior-1 ---------


        // You can use alternate behavior, if carousel image download bug occurs
        // Comment Behavior-1 and uncomment Behavior-2
        // --------- Behavior-2 ---------
        Utils.loadCarouselContents(
            message.carouselContent,
            object : DengageCallback<Array<Bitmap>> {
                override fun onError(error: DengageError) {
                    Toast.makeText(context, error.errorMessage ?: "", Toast.LENGTH_LONG).show()
                    Log.e("NotificationReceiver", error.errorMessage ?: "")
                }

                override fun onResult(result: Array<Bitmap>) {
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_landscape_left_image,
                        result[left]
                    )
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_landscape_current_image,
                        result[current]
                    )
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_landscape_right_image,
                        result[right]
                    )

                    // show message
                    val notificationManager = NotificationManagerCompat.from(context)
                    notificationManager.notify(
                        message.messageSource,
                        message.messageId,
                        notification
                    )
                }
            })
        // --------- Behavior-2 ---------

    }

    override fun onCarouselReRender(context: Context, intent: Intent?, message: Message?) {
        super.onCarouselReRender(context, intent, message)

        val items = message?.carouselContent
        if (items.isNullOrEmpty() || intent == null) return
        val bundle = intent.extras
        val prevIndex = bundle?.getInt("current")
        val navigation = bundle?.getString("navigation", "right")
        val size = items.size
        val current = if (navigation.equals("right")) {
            ((prevIndex ?: 0) + 1) % size
        } else {
            ((prevIndex ?: 0) - 1 + size) % size
        }
        val right = (current + 1) % size
        val left = (current - 1 + size) % size
        intent.putExtra("current", current)

        val itemTitle = items[current].title
        val itemDesc = items[current].description

        // set intents (next button, rigth button and item click)
        val itemIntent = getItemClickIntent(intent.extras, context.packageName)
        val leftIntent = getLeftItemIntent(intent.extras, context.packageName)
        val rightIntent = getRightItemIntent(intent.extras, context.packageName)
        val deleteIntent = getDeleteIntent(intent.extras, context.packageName)
        val contentIntent = getContentIntent(intent.extras, context.packageName)
        val carouseItemIntent = PendingIntent.getBroadcast(
            context, 0,
            itemIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val carouselLeftIntent = PendingIntent.getBroadcast(
            context, 1,
            leftIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val carouselRightIntent = PendingIntent.getBroadcast(
            context, 2,
            rightIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val deletePendingIntent = PendingIntent.getBroadcast(
            context, 4,
            deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val contentPendingIntent = PendingIntent.getBroadcast(
            context, 5,
            contentIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )

        // set views for the layout
        val collapsedView = RemoteViews(
            context.packageName,
            R.layout.den_carousel_collapsed
        )
        collapsedView.setTextViewText(R.id.den_carousel_title, message.title)
        collapsedView.setTextViewText(R.id.den_carousel_message, message.message)
        val carouselView = RemoteViews(
            context.packageName,
            R.layout.den_carousel_landscape
        )
        carouselView.setTextViewText(R.id.den_carousel_title, message.title)
        carouselView.setTextViewText(R.id.den_carousel_message, message.message)
        carouselView.setTextViewText(R.id.den_carousel_item_title, itemTitle)
        carouselView.setTextViewText(R.id.den_carousel_item_description, itemDesc)

        carouselView.setOnClickPendingIntent(R.id.den_carousel_left_arrow, carouselLeftIntent)
        carouselView.setOnClickPendingIntent(
            R.id.den_carousel_landscape_current_image,
            carouseItemIntent
        )
        carouselView.setOnClickPendingIntent(R.id.den_carousel_item_title, carouseItemIntent)
        carouselView.setOnClickPendingIntent(R.id.den_carousel_item_description, carouseItemIntent)
        carouselView.setOnClickPendingIntent(R.id.den_carousel_right_arrow, carouselRightIntent)

        val channelId = createNotificationChannel(context, message)

        // set your views for the notification
        val notification = NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setCustomContentView(collapsedView)
            .setCustomBigContentView(carouselView)
            .setContentIntent(contentPendingIntent)
            .setDeleteIntent(deletePendingIntent)
            .build()
        // show message again silently with next,prev and current item.
        notification.flags = Notification.FLAG_AUTO_CANCEL or Notification.FLAG_ONLY_ALERT_ONCE


        // --------- Behavior-1 ---------
        /*Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_landscape_left_image,
            items[left]
        )
        Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_landscape_current_image,
            items[current]
        )
        Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_landscape_right_image,
            items[right]
        )

        // show message
        val notificationManager = NotificationManagerCompat.from(context)
        notificationManager.notify(
            message.messageSource,
            message.messageId,
            notification
        )*/
        // --------- Behavior-1 ---------


        // You can use alternate behavior, if carousel image download bug occurs
        // Comment Behavior-1 and uncomment Behavior-2
        // --------- Behavior-2 ---------
        Utils.loadCarouselContents(
            message.carouselContent,
            object : DengageCallback<Array<Bitmap>> {
                override fun onError(error: DengageError) {
                    Toast.makeText(context, error.errorMessage ?: "", Toast.LENGTH_LONG).show()
                    Log.e("NotificationReceiver", error.errorMessage ?: "")
                }

                override fun onResult(result: Array<Bitmap>) {
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_landscape_left_image,
                        result[left]
                    )
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_landscape_current_image,
                        result[current]
                    )
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_landscape_right_image,
                        result[right]
                    )

                    // show message
                    val notificationManager = NotificationManagerCompat.from(context)
                    notificationManager.notify(
                        message.messageSource,
                        message.messageId,
                        notification
                    )
                }
            })
        // --------- Behavior-2 ---------
    }

    private fun createNotificationChannel(context: Context?, message: Message?): String {
        // generate new channel id for different sounds
        val soundUri = Utils.getSound(context, message?.sound)
        val channelId = UUID.randomUUID().toString()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationManager =
                context!!.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            // delete old notification channels
            val channels = notificationManager.notificationChannels
            if (channels != null && channels.size > 0) {
                for (channel in channels) {
                    notificationManager.deleteNotificationChannel(channel.id)
                }
            }
            val notificationChannel = NotificationChannel(
                channelId,
                Constants.CHANNEL_NAME,
                NotificationManager.IMPORTANCE_DEFAULT
            )
            val audioAttributes = AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                .build()
            notificationChannel.setSound(soundUri, audioAttributes)
            notificationManager.createNotificationChannel(notificationChannel)
        }
        return channelId
    }
}

Building Portrait Carousel

Copy the codes below to your receiver class.

class PushNotificationReceiver : NotificationReceiver() {

    override fun onCarouselRender(context: Context, intent: Intent?, message: Message?) {
        super.onCarouselRender(context, intent, message)

        val items = message?.carouselContent
        if (items.isNullOrEmpty() || intent == null) return
        val size = items.size
        val current = 0
        val left = (current - 1 + size) % size
        val right = (current + 1) % size

        val itemTitle = items[current].title
        val itemDesc = items[current].description

        // set intents (right button, left button, item click)
        val itemIntent = getItemClickIntent(intent.extras, context.packageName)
        val leftIntent = getLeftItemIntent(intent.extras, context.packageName)
        val rightIntent = getRightItemIntent(intent.extras, context.packageName)
        val deleteIntent = getDeleteIntent(intent.extras, context.packageName)
        val contentIntent = getContentIntent(intent.extras, context.packageName)
        val carouseItemIntent = PendingIntent.getBroadcast(
            context, 0,
            itemIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val carouselLeftIntent = PendingIntent.getBroadcast(
            context, 1,
            leftIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val carouselRightIntent = PendingIntent.getBroadcast(
            context, 2,
            rightIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val deletePendingIntent = PendingIntent.getBroadcast(
            context, 4,
            deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val contentPendingIntent = PendingIntent.getBroadcast(
            context, 5,
            contentIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )

        // set views for the layout
        val collapsedView = RemoteViews(
            context.packageName,
            R.layout.den_carousel_collapsed
        )
        collapsedView.setTextViewText(R.id.den_carousel_title, message.title)
        collapsedView.setTextViewText(R.id.den_carousel_message, message.message)
        val carouselView = RemoteViews(
            context.packageName,
            R.layout.den_carousel_portrait
        )
        carouselView.setTextViewText(R.id.den_carousel_title, message.title)
        carouselView.setTextViewText(R.id.den_carousel_message, message.message)
        carouselView.setTextViewText(R.id.den_carousel_item_title, itemTitle)
        carouselView.setTextViewText(R.id.den_carousel_item_description, itemDesc)

        carouselView.setOnClickPendingIntent(R.id.den_carousel_left_arrow, carouselLeftIntent)
        carouselView.setOnClickPendingIntent(
            R.id.den_carousel_portrait_current_image,
            carouseItemIntent
        )
        carouselView.setOnClickPendingIntent(R.id.den_carousel_item_title, carouseItemIntent)
        carouselView.setOnClickPendingIntent(R.id.den_carousel_item_description, carouseItemIntent)
        carouselView.setOnClickPendingIntent(R.id.den_carousel_right_arrow, carouselRightIntent)

        val channelId = createNotificationChannel(context, message)

        // set views for the notification
        val notification = NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setCustomContentView(collapsedView)
            .setCustomBigContentView(carouselView)
            .setContentIntent(contentPendingIntent)
            .setDeleteIntent(deletePendingIntent)
            .build()


        // --------- Behavior-1 ---------
        /*Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_portrait_left_image,
            items[left]
        )
        Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_portrait_current_image,
            items[current]
        )
        Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_portrait_right_image,
            items[right]
        )

        // show message
        val notificationManager = NotificationManagerCompat.from(context)
        notificationManager.notify(
            message.messageSource,
            message.messageId,
            notification
        )*/
        // --------- Behavior-1 ---------


        // You can use alternate behavior, if carousel image download bug occurs
        // Comment Behavior-1 and uncomment Behavior-2
        // --------- Behavior-2 ---------
        Utils.loadCarouselContents(
            message.carouselContent,
            object : DengageCallback<Array<Bitmap>> {
                override fun onError(error: DengageError) {
                    Toast.makeText(context, error.errorMessage ?: "", Toast.LENGTH_LONG).show()
                    Log.e("NotificationReceiver", error.errorMessage ?: "")
                }

                override fun onResult(result: Array<Bitmap>) {
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_portrait_left_image,
                        result[left]
                    )
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_portrait_current_image,
                        result[current]
                    )
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_portrait_right_image,
                        result[right]
                    )

                    // show message
                    val notificationManager = NotificationManagerCompat.from(context)
                    notificationManager.notify(
                        message.messageSource,
                        message.messageId,
                        notification
                    )
                }
            })
        // --------- Behavior-2 ---------

    }

    override fun onCarouselReRender(context: Context, intent: Intent?, message: Message?) {
        super.onCarouselReRender(context, intent, message)

        val items = message?.carouselContent
        if (items.isNullOrEmpty() || intent == null) return
        val bundle = intent.extras
        val prevIndex = bundle?.getInt("current")
        val navigation = bundle?.getString("navigation", "right")
        val size = items.size
        val current = if (navigation.equals("right")) {
            ((prevIndex ?: 0) + 1) % size
        } else {
            ((prevIndex ?: 0) - 1 + size) % size
        }
        val right = (current + 1) % size
        val left = (current - 1 + size) % size
        intent.putExtra("current", current)

        val itemTitle = items[current].title
        val itemDesc = items[current].description

        // set intents (next button, rigth button and item click)
        val itemIntent = getItemClickIntent(intent.extras, context.packageName)
        val leftIntent = getLeftItemIntent(intent.extras, context.packageName)
        val rightIntent = getRightItemIntent(intent.extras, context.packageName)
        val deleteIntent = getDeleteIntent(intent.extras, context.packageName)
        val contentIntent = getContentIntent(intent.extras, context.packageName)
        val carouseItemIntent = PendingIntent.getBroadcast(
            context, 0,
            itemIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val carouselLeftIntent = PendingIntent.getBroadcast(
            context, 1,
            leftIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val carouselRightIntent = PendingIntent.getBroadcast(
            context, 2,
            rightIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val deletePendingIntent = PendingIntent.getBroadcast(
            context, 4,
            deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )
        val contentPendingIntent = PendingIntent.getBroadcast(
            context, 5,
            contentIntent, PendingIntent.FLAG_UPDATE_CURRENT
        )

        // set views for the layout
        val collapsedView = RemoteViews(
            context.packageName,
            R.layout.den_carousel_collapsed
        )
        collapsedView.setTextViewText(R.id.den_carousel_title, message.title)
        collapsedView.setTextViewText(R.id.den_carousel_message, message.message)
        val carouselView = RemoteViews(
            context.packageName,
            R.layout.den_carousel_portrait
        )
        carouselView.setTextViewText(R.id.den_carousel_title, message.title)
        carouselView.setTextViewText(R.id.den_carousel_message, message.message)
        carouselView.setTextViewText(R.id.den_carousel_item_title, itemTitle)
        carouselView.setTextViewText(R.id.den_carousel_item_description, itemDesc)

        carouselView.setOnClickPendingIntent(R.id.den_carousel_left_arrow, carouselLeftIntent)
        carouselView.setOnClickPendingIntent(
            R.id.den_carousel_portrait_current_image,
            carouseItemIntent
        )
        carouselView.setOnClickPendingIntent(R.id.den_carousel_item_title, carouseItemIntent)
        carouselView.setOnClickPendingIntent(R.id.den_carousel_item_description, carouseItemIntent)
        carouselView.setOnClickPendingIntent(R.id.den_carousel_right_arrow, carouselRightIntent)

        val channelId = createNotificationChannel(context, message)

        // set your views for the notification
        val notification = NotificationCompat.Builder(context, channelId)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setCustomContentView(collapsedView)
            .setCustomBigContentView(carouselView)
            .setContentIntent(contentPendingIntent)
            .setDeleteIntent(deletePendingIntent)
            .build()
        // show message again silently with next,prev and current item.
        notification.flags = Notification.FLAG_AUTO_CANCEL or Notification.FLAG_ONLY_ALERT_ONCE


        // --------- Behavior-1 ---------
        /*Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_portrait_left_image,
            items[left]
        )
        Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_portrait_current_image,
            items[current]
        )
        Utils.loadCarouselImageToView(
            carouselView,
            R.id.den_carousel_portrait_right_image,
            items[right]
        )

        // show message
        val notificationManager = NotificationManagerCompat.from(context)
        notificationManager.notify(
            message.messageSource,
            message.messageId,
            notification
        )*/
        // --------- Behavior-1 ---------


        // You can use alternate behavior, if carousel image download bug occurs
        // Comment Behavior-1 and uncomment Behavior-2
        // --------- Behavior-2 ---------
        Utils.loadCarouselContents(
            message.carouselContent,
            object : DengageCallback<Array<Bitmap>> {
                override fun onError(error: DengageError) {
                    Toast.makeText(context, error.errorMessage ?: "", Toast.LENGTH_LONG).show()
                    Log.e("NotificationReceiver", error.errorMessage ?: "")
                }

                override fun onResult(result: Array<Bitmap>) {
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_portrait_left_image,
                        result[left]
                    )
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_portrait_current_image,
                        result[current]
                    )
                    carouselView.setImageViewBitmap(
                        R.id.den_carousel_portrait_right_image,
                        result[right]
                    )

                    // show message
                    val notificationManager = NotificationManagerCompat.from(context)
                    notificationManager.notify(
                        message.messageSource,
                        message.messageId,
                        notification
                    )
                }
            })
        // --------- Behavior-2 ---------
    }

    private fun createNotificationChannel(context: Context?, message: Message?): String {
        // generate new channel id for different sounds
        val soundUri = Utils.getSound(context, message?.sound)
        val channelId = UUID.randomUUID().toString()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationManager =
                context!!.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            // delete old notification channels
            val channels = notificationManager.notificationChannels
            if (channels != null && channels.size > 0) {
                for (channel in channels) {
                    notificationManager.deleteNotificationChannel(channel.id)
                }
            }
            val notificationChannel = NotificationChannel(
                channelId,
                Constants.CHANNEL_NAME,
                NotificationManager.IMPORTANCE_DEFAULT
            )
            val audioAttributes = AudioAttributes.Builder()
                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                .setUsage(AudioAttributes.USAGE_NOTIFICATION)
                .build()
            notificationChannel.setSound(soundUri, audioAttributes)
            notificationManager.createNotificationChannel(notificationChannel)
        }
        return channelId
    }
}