{"id":20340235,"url":"https://github.com/webengage/android-custom-push-layouts","last_synced_at":"2026-04-04T00:02:40.887Z","repository":{"id":82264984,"uuid":"163671757","full_name":"WebEngage/android-custom-push-layouts","owner":"WebEngage","description":"Android custom push layout samples","archived":false,"fork":false,"pushed_at":"2019-10-11T07:11:37.000Z","size":5483,"stargazers_count":7,"open_issues_count":1,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-11T23:18:10.188Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WebEngage.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-31T13:35:38.000Z","updated_at":"2024-06-29T04:31:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"970d1809-f169-4d63-af68-45cc3b0d5658","html_url":"https://github.com/WebEngage/android-custom-push-layouts","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/WebEngage/android-custom-push-layouts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebEngage%2Fandroid-custom-push-layouts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebEngage%2Fandroid-custom-push-layouts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebEngage%2Fandroid-custom-push-layouts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebEngage%2Fandroid-custom-push-layouts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WebEngage","download_url":"https://codeload.github.com/WebEngage/android-custom-push-layouts/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WebEngage%2Fandroid-custom-push-layouts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31382355,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T23:20:52.058Z","status":"ssl_error","status_checked_at":"2026-04-03T23:20:51.675Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T21:20:22.328Z","updated_at":"2026-04-04T00:02:40.697Z","avatar_url":"https://github.com/WebEngage.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Custom Push Notification Layouts\n\nWebEngage Android SDK has included two new functional interfaces in v3.10.1 which allows you to modify the default push notification layouts.\n\n**Note**: Make sure you follow the [Android notification layout guidelines](https://developer.android.com/training/notify-user/custom-notification) before creating your own custom layouts. Usually, collapsed view layouts are limited to 64 dp, and expanded view layouts are limited to 256 dp.\n\n\n**1. CustomPushRender**: Called for rendering push notifications. This is where you can set your custom layouts and notify push notifications.\n\n```java\npublic interface CustomPushRender {\n    /**\n     * @return: Return true if notification is rendered successfully, else return false.\n     */\n    boolean onRender(Context context, PushNotificationData pushNotificationData);\n}\n```\n\n\n**2. CustomPushRerender**: Called for re-rendering/updating push notifications. This is where you can update your push notifications.\n\n```java\npublic interface CustomPushRerender {\n    /**\n     * @return: Return true if notification is re-rendered successfully, else return false.\n     */\n    boolean onRerender(Context context, PushNotificationData pushNotificationData, Bundle extras);\n}\n```\n\n\nCustom push render callbacks are only called when you provide `we_custom_render: true` in the custom key-values while creating push campaign from WebEngage dashboard and CustomPushRender and CustomPushRerender implementations are registered using `WebEngage.registerCustomPushRenderCallback` and `WebEngage.registerCustomPushRerenderCallback` APIs.\n\nIf `onRender` or `onRerender` method returns false, then notification will not be displayed.\n\n\n### Push Notification Data\n\nThe instance of PushNotificationData available to you in the onRender and onRerender callbacks contains the details required to construct and show the push notification.\n\n\n### Tracking Push Notification Actions\n\nIn order to correctly track the push notification actions such as clicks, updates, dismissed, etc. in custom push notifications, it is mandatory to use the PendingIntents constructed through the APIs provided in the WebEngage's PendingIntentFactory class.\n\nPendingIntentFactory includes the APIs for constructing the following PendingIntents which must be set in the Notification for tracking different push notification actions.\n\n\n#### 1. Click PendingIntent\n\n`PendingIntent constructPushClickPendingIntent(Context context, PushNotificationData pushNotificationData, CallToAction cta, boolean autoCancel)` method returns a PendingIntent which can be set as PendingIntent for content intent or for any action button in your custom push notification.\n\n```java\n    boolean autoCancel = true;  // true if notification should be dismissed on click, else false\n    PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), autoCancel);\n    NotificationCompat.Builder builder = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n        ...\n        .setContentIntent(contentPendingIntent)\n        ...\n```\n\n\n#### 2. Delete PendingIntent\n\n`PendingIntent constructPushDeletePendingIntent(Context context, PushNotificationData pushNotificationData)` method returns a PendingIntent that must be set as delete intent in your notification, which will help WebEngage SDK to track push notification dismisses.\n\n```java\n    PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n    NotificationCompat.Builder builder = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n        ...\n        .setDeleteIntent(deletePendingIntent)\n        ...\n```\n\n\n#### 3. Rerender PendingIntent\n\n`PendingIntent constructRerenderPendingIntent(Context context, PushNotificationData pushNotificationData, String requestCodePrefix, Bundle extraData)` method returns a PendingIntent which will trigger the `onRerender` callback on click. This callback can be used to update/rerender your notification.\n\n*param* **String requestCodePrefix**: The request code of the returned PendingIntent is generated using the following code:\n\n```java\n    ...\n    int requestCode = (requestCodePrefix + pushNotificationData.getVariationId()).hashCode();\n    PendingIntent pendingIntent = PendingIntent.getService(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);\n    return pendingIntent;\n```\n\n*param* **Bundle extraData**: This bundle must include additional data required for rerendering the notification. This bundle will be passed in `boolean onRerender(Context context, PushNotificationData pushNotificationData, Bundle extraData)` method as extraData for updating the notification.\n\nFor E.g. You might want to update the push notification content when user selects a star in rating push notification. In order to mark the star(s) as selected, you might need an additional information that tells you which star was clicked. Such additional data can be passed in the extraData bundle.\n\n```java\n    Bundle rateClickExtraData = new Bundle();\n    rateClickExtraData.putInt(\"current\", i);\n    ...\n\n    PendingIntent rateClickPendingIntent = PendingIntentFactory.constructRerenderPendingIntent(context, pushNotificationData, \"rate_click_\" + i, rateClickExtraData);\n    ratingView.setOnClickPendingIntent(R.id.selected_star, rateClickPendingIntent);\n```\n\n\n#### 4. Carousel Browse PendingIntent\n\n`PendingIntent constructCarouselBrowsePendingIntent(Context context, PushNotificationData pushNotificationData, int newIndex, String navigation, String requestCodePrefix, Bundle extraData)` method returns a PendingIntent which will automatically track the carousel browse event on click of left/right arraows in the carousel push notification. It also triggers the `onRerender` callback which can be used to update the current carousel item.\n\n*param* **int newIndex**: This is the newly calculated index of the carousel item to be shown.\n\n*param* **String navigation**: This indicates the direction in which the carousel is browsed.\n\n```java\n    int currIndex = 0;\n    PendingIntent leftPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, currIndex, \"left\", \"carousel_left\", browseExtraData);\n    PendingIntent rightPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, currIndex, \"right\", \"carousel_right\", browseExtraData);\n    ...\n    carouselView.setOnClickPendingIntent(R.id.left_arraow, leftPendingIntent);\n    carouselView.setOnClickPendingIntent(R.id.right_arrow, rightPendingIntent);\n    ...\n```\n\n\n#### 5. Rating Submit PendingIntent\n\n`PendingIntent constructPushRatingSubmitPendingIntent(Context context, PushNotificationData pushNotificationData, int rateValue)` method takes an integer for rating as parameter which will track rating submit event on click of submit button in rating notification.\n\n*param* **int rateValue**: This is the last rating value selected by the user.\n\n```java\n    int currIndex = extraData.getInt(\"current\");  // current index can be obtained from extraData bundle provided while setting Click PendingIntent\n    PendingIntent rateSubmitPendingIntent = PendingIntentFactory.constructPushRatingSubmitPendingIntent(context, pushNotificationData, currIndex);\n    ratingView.setOnClickPendingIntent(R.id.rating_submit_button, rateSubmitPendingIntent);\n```\n\n**Note**: Any PendingIntents used in the push notification which is not provided by the above specified APIs, will not be tracked by the WebEngage Android SDK and hence will not be seen on the campaign stats page in your WebEngage dashboard.\n\nSample usage of these PendingIntents can be found in the code snippets of sample custom layouts given below.\n\n\n### Sample Custom Layouts\n\n**Prerequisites**:\n\n1. Add the following dependencies in your app-level build.gradle file.\n\n```gradle\n    // Firebase SDK\n    implementation 'com.google.firebase:firebase-core:16.0.6'\n    implementation 'com.google.firebase:firebase-messaging:17.3.4'\n\n    // WebEngage SDK\n    implementation 'com.webengage:android-sdk:3.+'\n```\n\nAlso integrate FCM with your app as shown [here](https://docs.webengage.com/docs/android-fcm-integration)\n\n\n2. Create implementations of CustomPushRender and CustomPushRerender interfaces as shown below.\n\n```java\npublic class MyPushRenderer implements CustomPushRender, CustomPushRerender {\n    @Override\n    public boolean onRender(Context context, PushNotificationData pushNotificationData) {\n        // render your notification here\n        return true;\n    }\n\n    @Override\n    public boolean onRerender(Context context, PushNotificationData pushNotificationData, Bundle bundle) {\n        // re-render your notification here\n        return true;\n    }\n}\n```\n\n\n3. Make sure to register for custom push render callbacks in your Application class as shown below.\n\n```java\npublic class MainApplication extends Application {\n    private static final String TAG = MainApplication.class.getSimpleName();\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        ...\n\n        initWebEngage();\n    }\n\n    private void initWebEngage() {\n        WebEngageConfig config = new WebEngageConfig.Builder()\n                    .setWebEngageKey(YOUR-WEBENGAGE-LICENSE-CODE)\n                    .setDebugMode(true)\n                    .build();\n\n        registerActivityLifecycleCallbacks(new WebEngageActivityLifeCycleCallbacks(this, config));\n\n        // Register for custom push render callbacks\n        MyPushRenderer myPushRenderer = new MyPushRenderer();\n        WebEngage.registerCustomPushRenderCallback(myPushRenderer);\n        WebEngage.registerCustomPushRerenderCallback(myPushRenderer);\n\n        try {\n            FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener\u003cInstanceIdResult\u003e() {\n                @Override\n                public void onSuccess(InstanceIdResult instanceIdResult) {\n                    String token = instanceIdResult.getToken();\n                    Log.d(TAG,  \"FCM token: \" + token);\n                    WebEngage.get().setRegistrationID(token);\n                }\n             });\n        } catch (Exception e) {\n            Log.e(TAG, \"Exception while getting FCM token\", e);\n        }\n    }\n}\n```\n\n\n4. Add `we_custom_render: true` under custom key-value pairs section in your push notification campaign.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" src=\"https://raw.githubusercontent.com/WebEngage/android-custom-push-layouts/master/images/customdata.png\"\u003e\n\u003c/p\u003e\n\n\nHere are some sample code snippets which might help you to build your own custom push notification layouts.\n\n\n### 1. Big Text Layout\n\nThe following code snippet demonstrates how to show Big Text notification without large icon using WebEngage CustomPushRender implementation.\n\n`MyPushRenderer.java`\n\n```java\npublic class MyPushRenderer implements CustomPushRender, CustomPushRerender {\n    ...\n\n    @Override\n    public boolean onRender(Context context, PushNotificationData pushNotificationData) {\n        if (pushNotificationData == null) {\n            return false;\n        }\n\n        if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O) {\n            // create notification channel\n        }\n\n        // Big text\n        if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.BIG_TEXT) {\n            PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n            PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), true);\n\n            NotificationCompat.Builder builder = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n                    .setSmallIcon(R.mipmap.ic_launcher)\n                    .setContentTitle(pushNotificationData.getTitle())\n                    .setContentText(pushNotificationData.getContentText())\n                    .setContentIntent(contentPendingIntent)\n                    .setStyle(new NotificationCompat.BigTextStyle()\n                            .setBigContentTitle(pushNotificationData.getBigTextStyleData().getBigContentTitle())\n                            .bigText(pushNotificationData.getBigTextStyleData().getBigText()))\n                    .setDeleteIntent(deletePendingIntent);\n\n            // actions\n            List\u003cCallToAction\u003e actionsList = pushNotificationData.getActions();\n            if (actionsList != null) {\n                for (CallToAction callToAction : actionsList) {\n                    PendingIntent ctaPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, callToAction, true);\n                    builder.addAction(0, callToAction.getText(), ctaPendingIntent);\n                }\n            }\n\n            Notification notification = builder.build();\n            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);\n            notificationManager.notify(pushNotificationData.getVariationId().hashCode(), notification);\n            Log.d(TAG, \"Rendered push notification from application: big text\");\n            return true;\n        }\n\n        return false;\n    }\n\n    ...\n\n}\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" src=\"https://raw.githubusercontent.com/WebEngage/android-custom-push-layouts/master/images/custom_bigtext.png\"\u003e\n\u003c/p\u003e\n\n\n### 2. Big Picture Layout\n\nThe below code sample demonstrates how to show multi-line text in a Big Picture notification style.\n\n[push_collapsed.xml](https://github.com/WebEngage/android-custom-push-layouts/blob/master/app/src/main/res/layout/push_collapsed.xml)\n\n[push_big_picture.xml](https://github.com/WebEngage/android-custom-push-layouts/blob/master/app/src/main/res/layout/push_big_picture.xml)\n\n`MyPushRenderer.java`\n\n```java\n    @Override\n    public boolean onRender(Context context, PushNotificationData pushNotificationData) {\n        if (pushNotificationData == null) {\n            return false;\n        }\n\n        if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O) {\n            // create notification channel\n        }\n\n        if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.BIG_PICTURE) {\n            PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n            PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), true);\n\n            RemoteViews collapsedView = new RemoteViews(context.getPackageName(), R.layout.push_collapsed);\n            collapsedView.setTextViewText(R.id.notificationTitle, pushNotificationData.getTitle());\n            collapsedView.setTextViewText(R.id.notificationText, pushNotificationData.getContentText());\n\n            Bitmap bigPicture = DownloadManager.getBitmapFromURL(pushNotificationData.getBigPictureStyleData().getBigPictureUrl(), false);\n\n            RemoteViews bigPictureView = new RemoteViews(context.getPackageName(), R.layout.push_big_picture);\n            bigPictureView.setTextViewText(R.id.notificationTitle, pushNotificationData.getBigPictureStyleData().getBigContentTitle());\n            bigPictureView.setTextViewText(R.id.notificationText, pushNotificationData.getBigPictureStyleData().getSummary());\n            bigPictureView.setInt(R.id.notificationText, \"setMaxLines\", 4);\n\n            if (bigPicture != null) {\n                bigPictureView.setViewVisibility(R.id.big_picture_imageview, View.VISIBLE);\n                bigPictureView.setImageViewBitmap(R.id.big_picture_imageview, bigPicture);\n            } else {\n                bigPictureView.setViewVisibility(R.id.big_picture_imageview, View.GONE);\n            }\n\n            NotificationCompat.Builder builder = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n                    .setSmallIcon(R.mipmap.ic_launcher)\n                    .setCustomContentView(collapsedView)\n                    .setCustomBigContentView(bigPictureView)\n                    .setContentIntent(contentPendingIntent)\n                    .setDeleteIntent(deletePendingIntent);\n\n            // Add custom actions\n            // Note: If you use NotificationCompat.DecoratedCustomViewStyle(), you can directly add actions to NotificationCompat.Builder without using custom layout (push_actions.xml) for actions.\n            List\u003cCallToAction\u003e actionsList = pushNotificationData.getActions();\n            if (actionsList != null \u0026\u0026 actionsList.size() \u003e 0) {\n                bigPictureView.setViewVisibility(R.id.push_actions, View.VISIBLE);\n                for (int i = 0; i \u003c actionsList.size(); i++) {\n                    CallToAction callToAction = actionsList.get(i);\n                    PendingIntent ctaPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, callToAction, true);\n                    int actionId = -1;\n                    switch (i) {\n                        case 0:\n                            actionId = R.id.action1;\n                            break;\n                        case 1:\n                            actionId = R.id.action2;\n                            break;\n                        case 2:\n                            actionId = R.id.action3;\n                            break;\n                    }\n                    if (actionId != -1) {\n                        bigPictureView.setViewVisibility(actionId, View.VISIBLE);\n                        bigPictureView.setTextViewText(actionId, callToAction.getText());\n                        bigPictureView.setOnClickPendingIntent(actionId, ctaPendingIntent);\n                    }\n                }\n            } else {\n                Log.d(TAG, \"no actions received\");\n                bigPictureView.setViewVisibility(R.id.push_actions, View.GONE);\n            }\n\n            Notification notification = builder.build();\n            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);\n            notificationManager.notify(pushNotificationData.getVariationId().hashCode(), notification);\n            Log.d(TAG, \"Rendered push notification from application: big picture\");\n            return true;\n        }\n\n        return false;\n    }\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" src=\"https://raw.githubusercontent.com/WebEngage/android-custom-push-layouts/master/images/custom_bigpicture.png\"\u003e\n\u003c/p\u003e\n\n\n### 3. Carousel Landscape Layout\n\nIn order to modify the carousel layout, it is important to implement both onRender and onRerender methods.\n\nThe following code shows how to display carousel notification without the item label over the image.\n\nInitially render the carousel notification from the onRender callback as shown below.\n\n[push_carousel_landscape.xml](https://github.com/WebEngage/android-custom-push-layouts/blob/master/app/src/main/res/layout/push_carousel_landscape.xml)\n\n`MyPushRenderer.java`\n\n```java\n    @Override\n    public boolean onRender(Context context, PushNotificationData pushNotificationData) {\n        if (pushNotificationData == null) {\n            return false;\n        }\n\n        if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O) {\n            // create notification channel\n        }\n\n        if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.CAROUSEL_V1) {\n            if (\"landscape\".equals(pushNotificationData.getCarouselV1Data().getMODE())) {\n                PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n                PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), true);\n\n                long when = System.currentTimeMillis();\n\n                Bundle browseExtraData = new Bundle();\n                browseExtraData.putLong(\"when\", when);\n                PendingIntent leftPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, 0, \"left\", \"carousel_left\", browseExtraData);\n                PendingIntent rightPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, 0, \"right\", \"carousel_right\", browseExtraData);\n\n                // Download all images and cache\n                List\u003cCarouselV1CallToAction\u003e ctas = pushNotificationData.getCarouselV1Data().getCallToActions();\n                for (CarouselV1CallToAction cta : ctas) {\n                    DownloadManager.downloadBitmap(cta.getImageURL());\n                }\n\n                RemoteViews collapsedView = new RemoteViews(context.getPackageName(), R.layout.push_collapsed);\n                collapsedView.setTextViewText(R.id.notificationTitle, pushNotificationData.getTitle());\n                collapsedView.setTextViewText(R.id.notificationText, pushNotificationData.getContentText());\n\n                CarouselV1CallToAction cta = ctas.get(0);\n                PendingIntent imagePendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, cta, false);\n\n                Bitmap img = DownloadManager.getBitmapFromURL(cta.getImageURL(), true);\n                if (img == null) {\n                    img = DownloadManager.getBitmapFromURL(cta.getImageURL(), false);\n                    if (img == null) {\n                        // Use a placeholder image\n                        img = BitmapFactory.decodeResource(context.getResources(), R.drawable.banner_android);\n                    }\n                }\n\n                RemoteViews carouselView = new RemoteViews(context.getPackageName(), R.layout.push_carousel_landscape);\n                carouselView.setTextViewText(R.id.notificationTitle, pushNotificationData.getCarouselV1Data().getBigContentTitle());\n                carouselView.setTextViewText(R.id.notificationText, pushNotificationData.getCarouselV1Data().getSummary());\n                carouselView.setImageViewBitmap(R.id.carousel_landscape_image, img);\n                carouselView.setOnClickPendingIntent(R.id.carousel_landscape_image, imagePendingIntent);\n                carouselView.setOnClickPendingIntent(R.id.left, leftPendingIntent);\n                carouselView.setOnClickPendingIntent(R.id.right, rightPendingIntent);\n\n                Notification notification = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n                        .setSmallIcon(R.mipmap.ic_launcher)\n                        .setCustomContentView(collapsedView)\n                        .setCustomBigContentView(carouselView)\n                        .setContentIntent(contentPendingIntent)\n                        .setDeleteIntent(deletePendingIntent)\n                        .build();\n\n                NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);\n                notificationManager.notify(pushNotificationData.getVariationId().hashCode(), notification);\n                Log.d(TAG, \"Rendered push notification from application: carousel\");\n                return true;\n            }\n        }\n\n        return false;\n    }\n```\n\n\nNow re-render the carousel notification in onRerender callback every time the user browses the carousel by clicking on left/right arrow as shown below.\n\n`MyPushRenderer.java`\n\n```java\n\t@Override\n\tpublic boolean onRerender(Context context, PushNotificationData pushNotificationData, Bundle bundle) {\n\t    if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O) {\n\t        // create notification channel id if not yet created\n\t    }\n\n\t    Bundle customData = pushNotificationData.getCustomData();\n\t    Log.d(TAG, \"custom data: \" + String.valueOf(customData) + \", extra data: \" + String.valueOf(bundle));\n\n\t    if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.CAROUSEL_V1) {\n\t        if (\"landscape\".equals(pushNotificationData.getCarouselV1Data().getMODE())) {\n                List\u003cCarouselV1CallToAction\u003e callToActionList = pushNotificationData.getCarouselV1Data().getCallToActions();\n                int size = callToActionList.size();\n                String navigation = bundle.getString(\"navigation\", \"right\");\n                int prevIndex = bundle.getInt(\"current\");\n                long when = bundle.getLong(\"when\");\n                int newIndex = 0;\n                if (navigation.equals(\"right\")) {\n                    newIndex = (prevIndex + 1) % size;\n                } else {\n                    newIndex = (prevIndex - 1 + size) % size;\n                }\n\n                PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n                PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), true);\n\n                Bundle browseExtraData = new Bundle();\n                browseExtraData.putLong(\"when\", when);\n                PendingIntent leftPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, newIndex, \"left\", \"carousel_left\", browseExtraData);\n                PendingIntent rightPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, newIndex, \"right\", \"carousel_right\", browseExtraData);\n\n                CarouselV1CallToAction cta = callToActionList.get(newIndex);\n                PendingIntent imagePendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, cta, false);\n\n                Bitmap img = DownloadManager.getBitmapFromURL(cta.getImageURL(), true);\n                if (img == null) {\n                    img = DownloadManager.getBitmapFromURL(cta.getImageURL(), false);\n                    if (img == null) {\n                        // Use a default/placeholder image\n                        img = BitmapFactory.decodeResource(context.getResources(), R.drawable.banner_android);\n                    }\n                }\n\n                RemoteViews collapsedView = new RemoteViews(context.getPackageName(), R.layout.push_collapsed);\n                collapsedView.setTextViewText(R.id.notificationTitle, pushNotificationData.getTitle());\n                collapsedView.setTextViewText(R.id.notificationText, pushNotificationData.getContentText());\n\n                RemoteViews carouselView = new RemoteViews(context.getPackageName(), R.layout.push_carousel_landscape);\n                carouselView.setTextViewText(R.id.notificationTitle, pushNotificationData.getCarouselV1Data().getBigContentTitle());\n                carouselView.setTextViewText(R.id.notificationText, pushNotificationData.getCarouselV1Data().getSummary());\n                carouselView.setImageViewBitmap(R.id.carousel_landscape_image, img);\n                carouselView.setOnClickPendingIntent(R.id.carousel_landscape_image, imagePendingIntent);\n                carouselView.setOnClickPendingIntent(R.id.left, leftPendingIntent);\n                carouselView.setOnClickPendingIntent(R.id.right, rightPendingIntent);\n\n                Notification notification = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n                        .setSmallIcon(R.mipmap.ic_launcher)\n                        .setCustomContentView(collapsedView)\n                        .setCustomBigContentView(carouselView)\n                        .setContentIntent(contentPendingIntent)\n                        .setDeleteIntent(deletePendingIntent)\n                        .setWhen(when)\n                        .build();\n\n                notification.flags |= Notification.FLAG_AUTO_CANCEL;\n                notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;\n\n                NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);\n                notificationManager.notify(pushNotificationData.getVariationId().hashCode(), notification);\n                Log.d(TAG, \"Re-rendered push notification: carousel\");\n                return true;\n            }\n\t    }\n\n\t    return false;\n\t}\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" src=\"https://raw.githubusercontent.com/WebEngage/android-custom-push-layouts/master/images/custom_carousel_landscape.png\"\u003e\n\u003c/p\u003e\n\n\n### 4. Carousel Portrait Layout\n\nThe following sample shows how to display carousel portrait notification using onRender and onRerender callbacks.\n\n[push_carousel_portrait.xml](https://github.com/WebEngage/android-custom-push-layouts/blob/master/app/src/main/res/layout/push_carousel_portrait.xml)\n\n`MyPushRenderer.java`\n\n```java\n    @Override\n    public boolean onRender(Context context, PushNotificationData pushNotificationData) {\n        if (pushNotificationData == null) {\n            return false;\n        }\n\n        if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O) {\n            // create notification channel\n        }\n\n        if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.CAROUSEL_V1) {\n        \tif (\"portrait\".equals(pushNotificationData.getCarouselV1Data().getMODE())) {\n                PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n                PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), true);\n\n                long when = System.currentTimeMillis();\n\n                Bundle browseExtraData = new Bundle();\n                browseExtraData.putLong(\"when\", when);\n                PendingIntent leftPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, 0, \"left\", \"carousel_left\", browseExtraData);\n                PendingIntent rightPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, 0, \"right\", \"carousel_right\", browseExtraData);\n\n                // Download all images and cache\n                List\u003cCarouselV1CallToAction\u003e ctaList = pushNotificationData.getCarouselV1Data().getCallToActions();\n                for (CarouselV1CallToAction cta : ctaList) {\n                    DownloadManager.downloadBitmap(cta.getImageURL());\n                }\n\n                RemoteViews collapsedView = new RemoteViews(context.getPackageName(), R.layout.push_collapsed);\n                collapsedView.setTextViewText(R.id.notificationTitle, pushNotificationData.getTitle());\n                collapsedView.setTextViewText(R.id.notificationText, pushNotificationData.getContentText());\n\n                int size = ctaList.size();\n                int curr = 0;\n                int right = (curr + 1) % size;\n                int left = (curr - 1 + size) % size;\n\n                CarouselV1CallToAction currCta = ctaList.get(curr);\n                CarouselV1CallToAction leftCta = ctaList.get(left);\n                CarouselV1CallToAction rightCta = ctaList.get(right);\n\n                Bitmap leftImg = DownloadManager.getBitmapFromURL(leftCta.getImageURL(), true);\n                if (leftImg == null) {\n                    leftImg = DownloadManager.getBitmapFromURL(leftCta.getImageURL(), false);\n                    if (leftImg == null) {\n                        // Image could not be downloaded. Set a placeholder image\n                        leftImg = BitmapFactory.decodeResource(context.getResources(), R.drawable.banner_android);\n                    }\n                }\n\n                Bitmap rightImg = DownloadManager.getBitmapFromURL(rightCta.getImageURL(), true);\n                if (rightImg == null) {\n                    rightImg = DownloadManager.getBitmapFromURL(rightCta.getImageURL(), false);\n                    if (rightImg == null) {\n                        // Image could not be downloaded. Set a placeholder image\n                        rightImg = BitmapFactory.decodeResource(context.getResources(), R.drawable.banner_android);\n                    }\n                }\n\n                Bitmap currImg = DownloadManager.getBitmapFromURL(currCta.getImageURL(), true);\n                if (currImg == null) {\n                    currImg = DownloadManager.getBitmapFromURL(currCta.getImageURL(), false);\n                    if (currImg == null) {\n                        // Image could not be downloaded. Set a placeholder image\n                        currImg = BitmapFactory.decodeResource(context.getResources(), R.drawable.banner_android);\n                    }\n                }\n\n                PendingIntent currImagePendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, currCta, false);\n\n                RemoteViews carouselView = new RemoteViews(context.getPackageName(), R.layout.push_carousel_portrait);\n                carouselView.setTextViewText(R.id.notificationTitle, pushNotificationData.getCarouselV1Data().getBigContentTitle());\n                carouselView.setTextViewText(R.id.notificationText, pushNotificationData.getCarouselV1Data().getSummary());\n                carouselView.setImageViewBitmap(R.id.carousel_curr_image, currImg);\n                carouselView.setOnClickPendingIntent(R.id.carousel_curr_image, currImagePendingIntent);\n                carouselView.setImageViewBitmap(R.id.carousel_left_image, leftImg);\n                carouselView.setImageViewBitmap(R.id.carousel_right_image, rightImg);\n                carouselView.setOnClickPendingIntent(R.id.left, leftPendingIntent);\n                carouselView.setOnClickPendingIntent(R.id.right, rightPendingIntent);\n\n                Notification notification = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n                        .setSmallIcon(R.mipmap.ic_launcher)\n                        .setCustomContentView(collapsedView)\n                        .setCustomBigContentView(carouselView)\n                        .setContentIntent(contentPendingIntent)\n                        .setDeleteIntent(deletePendingIntent)\n                        .build();\n\n                NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);\n                notificationManager.notify(pushNotificationData.getVariationId().hashCode(), notification);\n                Log.d(TAG, \"Rendered push notification from application: portrait carousel\");\n                return true;\n            }\n        }\n\n        return false;\n    }\n```\n\n\nRe-render on left/right arrow clicks.\n\n`MyPushRenderer.java`\n\n```java\n\t@Override\n\tpublic boolean onRerender(Context context, PushNotificationData pushNotificationData, Bundle bundle) {\n\t    if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O) {\n\t        // create notification channel id if not yet created\n\t    }\n\n\t    Bundle customData = pushNotificationData.getCustomData();\n\t    Log.d(TAG, \"custom data: \" + String.valueOf(customData) + \", extra data: \" + String.valueOf(bundle));\n\n\t    if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.CAROUSEL_V1) {\n\t        if (\"portrait\".equals(pushNotificationData.getCarouselV1Data().getMODE())) {\n                PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n                PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), true);\n\n                // Download all images and cache\n                List\u003cCarouselV1CallToAction\u003e ctaList = pushNotificationData.getCarouselV1Data().getCallToActions();\n                for (CarouselV1CallToAction cta : ctaList) {\n                    DownloadManager.downloadBitmap(cta.getImageURL());\n                }\n\n                long when = bundle.getLong(\"when\");\n                int prevIndex = bundle.getInt(\"current\");\n                String navigation = bundle.getString(\"navigation\", \"right\");\n                int size = ctaList.size();\n                int curr = 0;\n                if (navigation.equals(\"right\")) {\n                    curr = (prevIndex + 1) % size;\n                } else {\n                    curr = (prevIndex - 1 + size) % size;\n                }\n\n                int right = (curr + 1) % size;\n                int left = (curr - 1 + size) % size;\n\n                Bundle browseExtraData = new Bundle();\n                browseExtraData.putLong(\"when\", when);\n\n                PendingIntent leftPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, curr, \"left\", \"carousel_left\", browseExtraData);\n                PendingIntent rightPendingIntent = PendingIntentFactory.constructCarouselBrowsePendingIntent(context, pushNotificationData, curr, \"right\", \"carousel_right\", browseExtraData);\n\n                RemoteViews collapsedView = new RemoteViews(context.getPackageName(), R.layout.push_collapsed);\n                collapsedView.setTextViewText(R.id.notificationTitle, pushNotificationData.getTitle());\n                collapsedView.setTextViewText(R.id.notificationText, pushNotificationData.getContentText());\n\n                CarouselV1CallToAction currCta = ctaList.get(curr);\n                CarouselV1CallToAction leftCta = ctaList.get(left);\n                CarouselV1CallToAction rightCta = ctaList.get(right);\n\n                Bitmap leftImg = DownloadManager.getBitmapFromURL(leftCta.getImageURL(), true);\n                if (leftImg == null) {\n                    leftImg = DownloadManager.getBitmapFromURL(leftCta.getImageURL(), false);\n                    if (leftImg == null) {\n                        // Image could not be downloaded. Set a placeholder image\n                        leftImg = BitmapFactory.decodeResource(context.getResources(), R.drawable.banner_android);\n                    }\n                }\n\n                Bitmap rightImg = DownloadManager.getBitmapFromURL(rightCta.getImageURL(), true);\n                if (rightImg == null) {\n                    rightImg = DownloadManager.getBitmapFromURL(rightCta.getImageURL(), false);\n                    if (rightImg == null) {\n                        // Image could not be downloaded. Set a placeholder image\n                        rightImg = BitmapFactory.decodeResource(context.getResources(), R.drawable.banner_android);\n                    }\n                }\n\n                Bitmap currImg = DownloadManager.getBitmapFromURL(currCta.getImageURL(), true);\n                if (currImg == null) {\n                    currImg = DownloadManager.getBitmapFromURL(currCta.getImageURL(), false);\n                    if (currImg == null) {\n                        // Image could not be downloaded. Set a placeholder image\n                        currImg = BitmapFactory.decodeResource(context.getResources(), R.drawable.banner_android);\n                    }\n                }\n\n                PendingIntent currImagePendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, currCta, false);\n\n                RemoteViews carouselView = new RemoteViews(context.getPackageName(), R.layout.push_carousel_portrait);\n                carouselView.setTextViewText(R.id.notificationTitle, pushNotificationData.getCarouselV1Data().getBigContentTitle());\n                carouselView.setTextViewText(R.id.notificationText, pushNotificationData.getCarouselV1Data().getSummary());\n                carouselView.setImageViewBitmap(R.id.carousel_curr_image, currImg);\n                carouselView.setOnClickPendingIntent(R.id.carousel_curr_image, currImagePendingIntent);\n                carouselView.setImageViewBitmap(R.id.carousel_left_image, leftImg);\n                carouselView.setImageViewBitmap(R.id.carousel_right_image, rightImg);\n                carouselView.setOnClickPendingIntent(R.id.left, leftPendingIntent);\n                carouselView.setOnClickPendingIntent(R.id.right, rightPendingIntent);\n\n                Notification notification = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n                        .setSmallIcon(R.mipmap.ic_launcher)\n                        .setCustomContentView(collapsedView)\n                        .setCustomBigContentView(carouselView)\n                        .setContentIntent(contentPendingIntent)\n                        .setDeleteIntent(deletePendingIntent)\n                        .build();\n\n                notification.flags |= Notification.FLAG_AUTO_CANCEL;\n                notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;\n\n                NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);\n                notificationManager.notify(pushNotificationData.getVariationId().hashCode(), notification);\n                Log.d(TAG, \"Re-rendered push notification from application: portrait carousel\");\n                return true;\n            }\n\t    }\n\n\t    return false;\n\t}\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" src=\"https://raw.githubusercontent.com/WebEngage/android-custom-push-layouts/master/images/custom_carousel_portrait.png\"\u003e\n\u003c/p\u003e\n\n\n### 5. Rating Layout\n\nThis code snippet shows how to display the Rating notification layout using onRender and onRerender callbacks.\n\n[push_rating.xml](https://github.com/WebEngage/android-custom-push-layouts/blob/master/app/src/main/res/layout/push_rating.xml)\n\n`MyPushRenderer.java`\n\n```java\n    @Override\n    public boolean onRender(Context context, PushNotificationData pushNotificationData) {\n        if (pushNotificationData == null) {\n            return false;\n        }\n\n        if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O) {\n            // create notification channel\n        }\n\n        if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.RATING_V1) {\n            PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n            PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), true);\n\n            long when = System.currentTimeMillis();\n\n            RemoteViews collapsedView = new RemoteViews(context.getPackageName(), R.layout.push_collapsed);\n            collapsedView.setTextViewText(R.id.notificationTitle, pushNotificationData.getTitle());\n            collapsedView.setTextViewText(R.id.notificationText, pushNotificationData.getContentText());\n\n            RemoteViews npsView = new RemoteViews(context.getPackageName(), R.layout.push_rating);\n            npsView.setTextViewText(R.id.notificationTitle, pushNotificationData.getRatingV1().getBigContentTitle());\n            npsView.setTextViewText(R.id.notificationText, pushNotificationData.getRatingV1().getSummary());\n\n            if (pushNotificationData.getRatingV1().getImageUrl() != null) {\n                Bitmap img = DownloadManager.getBitmapFromURL(pushNotificationData.getRatingV1().getImageUrl(), false);\n                npsView.setViewVisibility(R.id.rate_frame, View.VISIBLE);\n                if (img != null) {\n                    npsView.setViewVisibility(R.id.rate_image, View.VISIBLE);\n                    npsView.setImageViewBitmap(R.id.rate_image, img);\n                } else {\n                    npsView.setInt(R.id.rate_frame, \"setBackgroundColor\", pushNotificationData.getRatingV1().getContentBackgroundColor());\n                }\n            }\n\n            if (pushNotificationData.getRatingV1().getContentTitle() != null) {\n                npsView.setViewVisibility(R.id.rate_frame, View.VISIBLE);\n                npsView.setViewVisibility(R.id.rate_title, View.VISIBLE);\n                npsView.setTextViewText(R.id.rate_title, pushNotificationData.getRatingV1().getContentTitle());\n            }\n\n            if (pushNotificationData.getRatingV1().getContentMessage() != null) {\n                npsView.setViewVisibility(R.id.rate_frame, View.VISIBLE);\n                npsView.setViewVisibility(R.id.rate_message, View.VISIBLE);\n                npsView.setTextViewText(R.id.rate_message, pushNotificationData.getRatingV1().getContentMessage());\n            }\n\n            for (int i = 1; i \u003c= 5; i++) {\n                Bundle rateClickExtraData = new Bundle();\n                rateClickExtraData.putInt(\"current\", i);\n                rateClickExtraData.putLong(\"when\", when);\n                final PendingIntent rateClickPendingIntent = PendingIntentFactory.constructRerenderPendingIntent(context, pushNotificationData, \"rate_click_\" + i, rateClickExtraData);\n\n                int id = context.getResources().getIdentifier(\"rate_\" + i, \"id\", context.getPackageName());\n                npsView.setOnClickPendingIntent(id, rateClickPendingIntent);\n            }\n\n            NotificationCompat.Builder builder = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n                    .setSmallIcon(R.mipmap.ic_launcher)\n                    .setCustomContentView(collapsedView)\n                    .setCustomBigContentView(npsView)\n                    .setContentIntent(contentPendingIntent)\n                    .setDeleteIntent(deletePendingIntent)\n                    .setStyle(new NotificationCompat.DecoratedCustomViewStyle());\n\n            Notification notification = builder.build();\n            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);\n            notificationManager.notify(pushNotificationData.getVariationId().hashCode(), notification);\n            Log.d(TAG, \"Rendered push notification from application: rating\");\n            return true;\n        }\n\n        return false;\n    }\n```\n\nRe-render the rating notification in onRerender callback whenever the user selects/changes the rating as shown below.\n\n`MyPushRenderer.java`\n\n```java\n@Override\npublic boolean onRerender(Context context, PushNotificationData pushNotificationData, Bundle bundle) {\n    if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O) {\n        // create notification channel id if not yet created\n    }\n\n    if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.RATING_V1) {\n        int currIndex = bundle.getInt(\"current\");\n        long when = bundle.getLong(\"when\");\n\n        RemoteViews collapsedView = new RemoteViews(context.getPackageName(), R.layout.push_collapsed);\n        collapsedView.setTextViewText(R.id.notificationTitle, pushNotificationData.getTitle());\n        collapsedView.setTextViewText(R.id.notificationText, pushNotificationData.getContentText());\n\n        RemoteViews npsView = new RemoteViews(context.getPackageName(), R.layout.push_rating);\n        npsView.setTextViewText(R.id.notificationTitle, pushNotificationData.getRatingV1().getBigContentTitle());\n        npsView.setTextViewText(R.id.notificationText, pushNotificationData.getRatingV1().getSummary());\n\n        if (pushNotificationData.getRatingV1().getImageUrl() != null) {\n            Bitmap img = DownloadManager.getBitmapFromURL(pushNotificationData.getRatingV1().getImageUrl(), false);\n            npsView.setViewVisibility(R.id.rate_frame, View.VISIBLE);\n            if (img != null) {\n                npsView.setViewVisibility(R.id.rate_image, View.VISIBLE);\n                npsView.setImageViewBitmap(R.id.rate_image, img);\n            } else {\n                npsView.setInt(R.id.rate_frame, \"setBackgroundColor\", pushNotificationData.getRatingV1().getContentBackgroundColor());\n            }\n        }\n\n        if (pushNotificationData.getRatingV1().getContentTitle() != null) {\n            npsView.setViewVisibility(R.id.rate_frame, View.VISIBLE);\n            npsView.setViewVisibility(R.id.rate_title, View.VISIBLE);\n            npsView.setTextViewText(R.id.rate_title, pushNotificationData.getRatingV1().getContentTitle());\n        }\n\n        if (pushNotificationData.getRatingV1().getContentMessage() != null) {\n            npsView.setViewVisibility(R.id.rate_frame, View.VISIBLE);\n            npsView.setViewVisibility(R.id.rate_message, View.VISIBLE);\n            npsView.setTextViewText(R.id.rate_message, pushNotificationData.getRatingV1().getContentMessage());\n        }\n\n        for (int i = 1; i \u003c= 5; i++) {\n            Bundle rateClickExtraData = new Bundle();\n            rateClickExtraData.putInt(\"current\", i);\n            rateClickExtraData.putLong(\"when\", when);\n            PendingIntent rateClickPendingIntent = PendingIntentFactory.constructRerenderPendingIntent(context, pushNotificationData, \"rate_click_\" + i, rateClickExtraData);\n\n            int id = context.getResources().getIdentifier(\"rate_\" + i, \"id\", context.getPackageName());\n            npsView.setOnClickPendingIntent(id, rateClickPendingIntent);\n\n            // Here you can use any resource for selected and unselected rating icon\n            if (i \u003c= currIndex) {\n                npsView.setImageViewResource(id, R.drawable.star_selected);\n            } else {\n                npsView.setImageViewResource(id, R.drawable.star_unselected);\n            }\n        }\n\n        PendingIntent rateSubmitPendingIntent = PendingIntentFactory.constructPushRatingSubmitPendingIntent(context, pushNotificationData, currIndex);\n        npsView.setOnClickPendingIntent(R.id.rate_submit, rateSubmitPendingIntent);\n\n        PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n        PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), true);\n\n        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n                .setSmallIcon(R.mipmap.ic_launcher)\n                .setCustomContentView(collapsedView)\n                .setCustomBigContentView(npsView)\n                .setContentIntent(contentPendingIntent)\n                .setDeleteIntent(deletePendingIntent)\n                .setStyle(new NotificationCompat.DecoratedCustomViewStyle());\n\n        Notification notification = builder.build();\n        notification.flags |= Notification.FLAG_AUTO_CANCEL;\n        notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;\n\n        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);\n        notificationManager.notify(pushNotificationData.getVariationId().hashCode(), notification);\n        Log.d(TAG, \"Re-rendered push notification: rating\");\n        return true;\n    }\n\n    return false;\n}\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" src=\"https://raw.githubusercontent.com/WebEngage/android-custom-push-layouts/master/images/custom_rating.png\"\u003e\n\u003c/p\u003e\n\n\n### 6. HTML-Styled Text and Banner Layout\n\n**Campaign settings**\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" src=\"https://raw.githubusercontent.com/WebEngage/android-custom-push-layouts/master/images/html_text.png\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" src=\"https://raw.githubusercontent.com/WebEngage/android-custom-push-layouts/master/images/html_customdata.png\"\u003e\n\u003c/p\u003e\n\nThe following code snippet shows how to display the HTML styled **Text** push notifications using onRender callback.\n\n`MyPushRenderer.java`\n\n```java\npublic class MyPushRenderer implements CustomPushRender {\n    ...\n\n    @Override\n    public boolean onRender(Context context, PushNotificationData pushNotificationData) {\n        if (pushNotificationData == null) {\n            return false;\n        }\n\n        if (Build.VERSION.SDK_INT \u003e= Build.VERSION_CODES.O) {\n            // create notification channel\n        }\n\n        // HTML Styled Big Text\n        if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.BIG_TEXT \u0026\u0026 \"html\".equalsIgnoreCase(customData.getString(\"format\", \"\"))) {\n            PendingIntent deletePendingIntent = PendingIntentFactory.constructPushDeletePendingIntent(context, pushNotificationData);\n            PendingIntent contentPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, pushNotificationData.getPrimeCallToAction(), true);\n\n            Spanned styledTitle = HtmlCompat.fromHtml(pushNotificationData.getTitle(), HtmlCompat.FROM_HTML_MODE_COMPACT);\n            Spanned styledText = HtmlCompat.fromHtml(pushNotificationData.getContentText(), HtmlCompat.FROM_HTML_MODE_COMPACT);\n            Spanned styledBigTitle = HtmlCompat.fromHtml(pushNotificationData.getBigTextStyleData().getBigContentTitle(), HtmlCompat.FROM_HTML_MODE_COMPACT);\n            Spanned styledBigText = HtmlCompat.fromHtml(pushNotificationData.getBigTextStyleData().getBigText(), HtmlCompat.FROM_HTML_MODE_COMPACT);\n\n            NotificationCompat.Builder builder = new NotificationCompat.Builder(context, MY_CHANNEL_ID)\n                .setSmallIcon(R.mipmap.ic_launcher)\n                .setContentTitle(styledTitle)\n                .setContentText(styledText)\n                .setContentIntent(contentPendingIntent)\n                .setStyle(new NotificationCompat.BigTextStyle()\n                    .setBigContentTitle(styledBigTitle)\n                    .bigText(styledBigText))\n                .setDeleteIntent(deletePendingIntent);\n\n            // actions\n            List\u003cCallToAction\u003e actionsList = pushNotificationData.getActions();\n            if (actionsList != null) {\n                for (CallToAction callToAction : actionsList) {\n                    PendingIntent ctaPendingIntent = PendingIntentFactory.constructPushClickPendingIntent(context, pushNotificationData, callToAction, true);\n                    builder.addAction(0, callToAction.getText(), ctaPendingIntent);\n                }\n            }\n\n            Notification notification = builder.build();\n            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);\n            notificationManager.notify(pushNotificationData.getVariationId().hashCode(), notification);\n            Log.d(TAG, \"Rendered push notification from application: html styled big text\");\n            return true;\n        }\n        ...\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"460\" src=\"https://raw.githubusercontent.com/WebEngage/android-custom-push-layouts/master/images/custom_html.png\"\u003e\n\u003c/p\u003e\n\nSimilarly, for **Banner** push notifications refer [Big Picture Layout](https://github.com/WebEngage/android-custom-push-layouts#2-big-picture-layout) and modify the code as shown below.\n\n```java\n    ...\n    // HTML Styled Big Picture\n    if (pushNotificationData.getStyle() == WebEngageConstant.STYLE.BIG_PICTURE \u0026\u0026 \"html\".equalsIgnoreCase(customData.getString(\"format\", \"\"))) {\n        // Format the HTML styled texts\n        Spanned styledTitle = HtmlCompat.fromHtml(pushNotificationData.getTitle(), HtmlCompat.FROM_HTML_MODE_COMPACT);\n        Spanned styledText = HtmlCompat.fromHtml(pushNotificationData.getContentText(), HtmlCompat.FROM_HTML_MODE_COMPACT);\n\n        Spanned styledBigTitle = HtmlCompat.fromHtml(pushNotificationData.getBigPictureStyleData().getBigContentTitle(), HtmlCompat.FROM_HTML_MODE_COMPACT);    \n        Spanned styledBigText = HtmlCompat.fromHtml(pushNotificationData.getBigPictureStyleData().getSummary(), HtmlCompat.FROM_HTML_MODE_COMPACT);\n        ...\n\n        collapsedView.setTextViewText(R.id.notificationTitle, styledTitle);\n        collapsedView.setTextViewText(R.id.notificationText, styledText);\n        ...\n\n        bigPictureView.setTextViewText(R.id.notificationTitle, styledBigTitle);\n        bigPictureView.setTextViewText(R.id.notificationText, styledBigText);\n        ...\n    }\n    ...\n```\n\n\nThese code samples are simple examples for modifying and rendering custom layouts for push notifications sent through WebEngage. You can render even more complex notification layouts as per your requirements.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebengage%2Fandroid-custom-push-layouts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebengage%2Fandroid-custom-push-layouts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebengage%2Fandroid-custom-push-layouts/lists"}