From bd10279149fcc52bac8498d07f540e97c0ea16c8 Mon Sep 17 00:00:00 2001 From: anush Date: Wed, 30 Oct 2024 17:08:41 +0530 Subject: [PATCH 01/14] task(SDK-4057) - Revamped Timer Notification Template - Refactors the code in PushProviders.java to make it more modular - Adds a service which will now show the timer template --- clevertap-core/src/main/AndroidManifest.xml | 2 + .../clevertap/android/sdk/CleverTapAPI.java | 24 ++ .../sdk/pushnotification/PushProviders.java | 329 ++++++++++-------- .../PushTemplateNotificationHandler.java | 36 +- .../android/pushtemplates/TemplateRenderer.kt | 15 +- .../android/pushtemplates/TemplateType.kt | 2 +- .../pushtemplates/TimerTemplateService.kt | 58 +++ sample/src/main/AndroidManifest.xml | 5 + 8 files changed, 315 insertions(+), 156 deletions(-) create mode 100644 clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TimerTemplateService.kt diff --git a/clevertap-core/src/main/AndroidManifest.xml b/clevertap-core/src/main/AndroidManifest.xml index 61d41f7ed..3eb8033b1 100644 --- a/clevertap-core/src/main/AndroidManifest.xml +++ b/clevertap-core/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + diff --git a/clevertap-core/src/main/java/com/clevertap/android/sdk/CleverTapAPI.java b/clevertap-core/src/main/java/com/clevertap/android/sdk/CleverTapAPI.java index 4d14d7676..c4ce104dd 100644 --- a/clevertap-core/src/main/java/com/clevertap/android/sdk/CleverTapAPI.java +++ b/clevertap-core/src/main/java/com/clevertap/android/sdk/CleverTapAPI.java @@ -31,6 +31,8 @@ import androidx.annotation.RestrictTo; import androidx.annotation.RestrictTo.Scope; import androidx.annotation.WorkerThread; +import androidx.core.app.NotificationCompat; + import com.clevertap.android.sdk.cryption.CryptHandler; import com.clevertap.android.sdk.displayunits.DisplayUnitListener; import com.clevertap.android.sdk.displayunits.model.CleverTapDisplayUnit; @@ -3241,6 +3243,28 @@ public void renderPushNotificationOnCallerThread(@NonNull INotificationRenderer } + @RestrictTo(Scope.LIBRARY_GROUP) + public NotificationCompat.Builder getPushNotificationOnCallerThread(@NonNull INotificationRenderer iNotificationRenderer, Context context, + Bundle extras) { + CleverTapInstanceConfig config = coreState.getConfig(); + try { + synchronized (coreState.getPushProviders().getPushRenderingLock()) { + config.getLogger().verbose(config.getAccountId(), + "returning push on caller thread with id = " + Thread.currentThread().getId()); + coreState.getPushProviders().setPushNotificationRenderer(iNotificationRenderer); + if (extras != null && extras.containsKey(Constants.PT_NOTIF_ID)) { + return coreState.getPushProviders()._getNotification(context, extras, + extras.getInt(Constants.PT_NOTIF_ID)); + } else { + return coreState.getPushProviders()._getNotification(context, extras, Constants.EMPTY_NOTIFICATION_ID); + } + } + } catch (Throwable t) { + config.getLogger().debug(config.getAccountId(), "Failed to process renderPushNotification()", t); + return null; + } + } + /** * Retrieves a notification bitmap with a specified timeout and size constraint. * diff --git a/clevertap-core/src/main/java/com/clevertap/android/sdk/pushnotification/PushProviders.java b/clevertap-core/src/main/java/com/clevertap/android/sdk/pushnotification/PushProviders.java index e74cc427f..0d2429534 100644 --- a/clevertap-core/src/main/java/com/clevertap/android/sdk/pushnotification/PushProviders.java +++ b/clevertap-core/src/main/java/com/clevertap/android/sdk/pushnotification/PushProviders.java @@ -35,7 +35,6 @@ import com.clevertap.android.sdk.Logger; import com.clevertap.android.sdk.ManifestInfo; import com.clevertap.android.sdk.StorageHelper; -import com.clevertap.android.sdk.Utils; import com.clevertap.android.sdk.db.BaseDatabaseManager; import com.clevertap.android.sdk.db.DBAdapter; import com.clevertap.android.sdk.interfaces.AudibleNotification; @@ -66,6 +65,17 @@ @RestrictTo(Scope.LIBRARY_GROUP) public class PushProviders implements CTPushProviderListener { + public static class NotificationResult { + public final NotificationCompat.Builder builder; + public final int notificationId; + + public NotificationResult(NotificationCompat.Builder builder, int notificationId) { + this.builder = builder; + this.notificationId = notificationId; + } + } + + private static final int DEFAULT_FLEX_INTERVAL = 5; private static final int PING_FREQUENCY_VALUE = 240; private static final String PF_JOB_ID = "pfjobid"; @@ -148,7 +158,41 @@ private PushProviders( * @param extras The {@link Bundle} object received by the broadcast receiver * @param notificationId A custom id to build a notification */ - public void _createNotification(final Context context, final Bundle extras, final int notificationId) { + public void _createNotification(final Context context, final Bundle extras, int notificationId) { + try { + NotificationResult result = getPreparedNotificationBuilder(context, extras, notificationId); + if (result.builder != null) { + triggerNotification(result.builder, result.notificationId); + storePushNotification(extras); + } + } catch (Throwable t) { + config.getLogger() + .debug(config.getAccountId(), "Couldn't render notification: ", t); + } + } + + public NotificationCompat.Builder _getNotification(final Context context, final Bundle extras, int notificationId) { + try { + NotificationResult result = getPreparedNotificationBuilder(context, extras, notificationId); + if (result.builder != null) { + storePushNotification(extras); + return result.builder; + } + } catch (Throwable t) { + config.getLogger() + .debug(config.getAccountId(), "Couldn't get notification: ", t); + } + return null; + } + + private NotificationResult getPreparedNotificationBuilder(final Context context, final Bundle extras, int notificationId) { + preProcessNotification(extras); + int generatedNotificationId = generateNotificationId(notificationId, extras); + NotificationCompat.Builder builder = prepareNotificationBuilder(context, extras, generatedNotificationId); + return new NotificationResult(builder, generatedNotificationId); + } + + private void preProcessNotification(Bundle extras) { if (extras == null || extras.get(Constants.NOTIFICATION_TAG) == null) { return; } @@ -160,55 +204,40 @@ public void _createNotification(final Context context, final Bundle extras, fina return; } - try { - boolean isSilent = extras.getString(Constants.WZRK_PUSH_SILENT, "").equalsIgnoreCase("true"); - if (isSilent) { - analyticsManager.pushNotificationViewedEvent(extras); - return; + boolean isSilent = extras.getString(Constants.WZRK_PUSH_SILENT, "").equalsIgnoreCase("true"); + if (isSilent) { + analyticsManager.pushNotificationViewedEvent(extras); + return; + } + String extrasFrom = extras.getString(Constants.EXTRAS_FROM); + if (extrasFrom == null || !extrasFrom.equals("PTReceiver")) { + config.getLogger() + .debug(config.getAccountId(), + "Handling notification: " + extras); + + if (extras.getString(Constants.WZRK_PUSH_ID) != null) { + if (baseDatabaseManager.loadDBAdapter(context) + .doesPushNotificationIdExist( + extras.getString(Constants.WZRK_PUSH_ID))) { + config.getLogger().debug(config.getAccountId(), + "Push Notification already rendered, not showing again"); + return; + } } - String extrasFrom = extras.getString(Constants.EXTRAS_FROM); - if (extrasFrom == null || !extrasFrom.equals("PTReceiver")) { + String notifMessage = iNotificationRenderer.getMessage(extras); + notifMessage = (notifMessage != null) ? notifMessage : ""; + if (notifMessage.isEmpty()) { + //silent notification config.getLogger() - .debug(config.getAccountId(), - "Handling notification: " + extras); - - if (extras.getString(Constants.WZRK_PUSH_ID) != null) { - if (baseDatabaseManager.loadDBAdapter(context) - .doesPushNotificationIdExist( - extras.getString(Constants.WZRK_PUSH_ID))) { - config.getLogger().debug(config.getAccountId(), - "Push Notification already rendered, not showing again"); - return; - } - } - String notifMessage = iNotificationRenderer.getMessage(extras); - notifMessage = (notifMessage != null) ? notifMessage : ""; - if (notifMessage.isEmpty()) { - //silent notification - config.getLogger() - .verbose(config.getAccountId(), - "Push notification message is empty, not rendering"); - baseDatabaseManager.loadDBAdapter(context) - .storeUninstallTimestamp(); - String pingFreq = extras.getString("pf", ""); - if (!TextUtils.isEmpty(pingFreq)) { - updatePingFrequencyIfNeeded(context, Integer.parseInt(pingFreq)); - } - return; + .verbose(config.getAccountId(), + "Push notification message is empty, not rendering"); + baseDatabaseManager.loadDBAdapter(context) + .storeUninstallTimestamp(); + String pingFreq = extras.getString("pf", ""); + if (!TextUtils.isEmpty(pingFreq)) { + updatePingFrequencyIfNeeded(context, Integer.parseInt(pingFreq)); } } - - String notifTitle = iNotificationRenderer.getTitle(extras, - context);//extras.getString(Constants.NOTIF_TITLE, "");// uncommon - getTitle() - notifTitle = notifTitle.isEmpty() ? context.getApplicationInfo().name - : notifTitle;//common - triggerNotification(context, extras, notificationId); - } catch (Throwable t) { - // Occurs if the notification image was null - // Let's return, as we couldn't get a handle on the app's icon - // Some devices throw a PackageManager* exception too - config.getLogger() - .debug(config.getAccountId(), "Couldn't render notification: ", t); } } @@ -876,74 +905,110 @@ public void setPushNotificationRenderer(@NonNull INotificationRenderer iNotifica this.iNotificationRenderer = iNotificationRenderer; } - private void triggerNotification(Context context, Bundle extras, int notificationId) { + private void triggerNotification(@NonNull NotificationCompat.Builder nb, int notificationId) { + NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); + Notification n = nb.build(); + notificationManager.notify(notificationId, n); + config.getLogger().debug(config.getAccountId(), "Rendered notification: " + n); + } + + public NotificationCompat.Builder prepareNotificationBuilder(Context context, Bundle extras, int notificationId) { NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); if (notificationManager == null) { String notificationManagerError = "Unable to render notification, Notification Manager is null."; config.getLogger().debug(config.getAccountId(), notificationManagerError); - return; + return null; } - String channelId = extras.getString(Constants.WZRK_CHANNEL_ID, ""); - String updatedChannelId = null; final boolean requiresChannelId = VERSION.SDK_INT >= VERSION_CODES.O; - + NotificationCompat.Builder nb; if (requiresChannelId) { - int messageCode = -1; - String value = ""; - - if (channelId.isEmpty()) { - messageCode = Constants.CHANNEL_ID_MISSING_IN_PAYLOAD; - value = extras.toString(); - } else if (notificationManager.getNotificationChannel(channelId) == null) { - messageCode = Constants.CHANNEL_ID_NOT_REGISTERED; - value = channelId; - } - if (messageCode != -1) { - ValidationResult channelIdError = ValidationResultFactory.create(512, messageCode, value); - config.getLogger().debug(config.getAccountId(), channelIdError.getErrorDesc()); - validationResultStack.pushValidationResult(channelIdError); + String updatedChannelId = getNotificationChannelId(notificationManager, context, extras); + if (updatedChannelId == null) { + return null; } + nb = new NotificationCompat.Builder(context, updatedChannelId); + } else { + nb = new NotificationCompat.Builder(context); + } - // get channel using channel id from push payload. If channel id is null or empty then create default - updatedChannelId = CTXtensions.getOrCreateChannel(notificationManager, channelId, context); - // if no channel gets created then do not render push - if (updatedChannelId == null || updatedChannelId.trim().isEmpty()) { - config.getLogger() - .debug(config.getAccountId(), "Not rendering Push since channel id is null or blank."); - return; - } + int smallIcon = getSmallIcon(context); + iNotificationRenderer.setSmallIcon(smallIcon, context); - // if channel is blocked by user then do not render push - if (!CTXtensions.isNotificationChannelEnabled(context,updatedChannelId)) { - config.getLogger() - .verbose(config.getAccountId(), - "Not rendering push notification as channel = " + updatedChannelId + " is blocked by user"); - return; - } + setNotificationPriority(nb, extras); + setNotificationBadge(nb, extras); + + if (iNotificationRenderer instanceof AudibleNotification) { + nb = ((AudibleNotification) iNotificationRenderer).setSound(context, extras, nb, config); + } + + // Generate the nb based on the rendered + nb = iNotificationRenderer.renderNotification(extras, context, nb, config, notificationId); + + return nb; + } - config.getLogger().debug(config.getAccountId(), "Rendering Push on channel = " + updatedChannelId); + @RequiresApi(api = VERSION_CODES.O) + private String getNotificationChannelId(NotificationManager notificationManager, Context context, Bundle extras) { + String channelId = extras.getString(Constants.WZRK_CHANNEL_ID, ""); + String updatedChannelId; + int messageCode = -1; + String value = ""; + + if (channelId.isEmpty()) { + messageCode = Constants.CHANNEL_ID_MISSING_IN_PAYLOAD; + value = extras.toString(); + } else if (notificationManager.getNotificationChannel(channelId) == null) { + messageCode = Constants.CHANNEL_ID_NOT_REGISTERED; + value = channelId; + } + if (messageCode != -1) { + ValidationResult channelIdError = ValidationResultFactory.create(512, messageCode, value); + config.getLogger().debug(config.getAccountId(), channelIdError.getErrorDesc()); + validationResultStack.pushValidationResult(channelIdError); + } + + // Get or create the channel using the channel ID from the push payload + updatedChannelId = CTXtensions.getOrCreateChannel(notificationManager, channelId, context); + + // If no channel is created, do not render the push notification + if (updatedChannelId == null || updatedChannelId.trim().isEmpty()) { + config.getLogger().debug(config.getAccountId(), "Not rendering Push since channel id is null or blank."); + return null; + } + + // If the channel is blocked by the user, do not render the push notification + if (!CTXtensions.isNotificationChannelEnabled(context, updatedChannelId)) { + config.getLogger().verbose(config.getAccountId(), + "Not rendering push notification as channel = " + updatedChannelId + " is blocked by user"); + return null; } - int smallIcon; + config.getLogger().debug(config.getAccountId(), "Rendering Push on channel = " + updatedChannelId); + return updatedChannelId; // Return the valid channel ID + } + + + private int getSmallIcon(Context context) { try { - String x = ManifestInfo.getInstance(context).getNotificationIcon(); - if (x == null) { + String iconName = ManifestInfo.getInstance(context).getNotificationIcon(); + if (iconName == null) { throw new IllegalArgumentException(); } - smallIcon = context.getResources().getIdentifier(x, "drawable", context.getPackageName()); + int smallIcon = context.getResources().getIdentifier(iconName, "drawable", context.getPackageName()); if (smallIcon == 0) { throw new IllegalArgumentException(); } + return smallIcon; } catch (Throwable t) { - smallIcon = DeviceInfo.getAppIconAsIntId(context); + return DeviceInfo.getAppIconAsIntId(context); // Fallback to app icon } + } - iNotificationRenderer.setSmallIcon(smallIcon, context); - + private void setNotificationPriority(NotificationCompat.Builder nb, Bundle extras) { int priorityInt = NotificationCompat.PRIORITY_DEFAULT; String priority = extras.getString(Constants.NOTIF_PRIORITY); if (priority != null) { @@ -954,7 +1019,38 @@ private void triggerNotification(Context context, Bundle extras, int notificatio priorityInt = NotificationCompat.PRIORITY_MAX; } } + nb.setPriority(priorityInt); + } + + private void setNotificationBadge(NotificationCompat.Builder nb, Bundle extras) { + // Set badge icon + String badgeIconParam = extras.getString(Constants.WZRK_BADGE_ICON, null); + if (badgeIconParam != null) { + try { + int badgeIconType = Integer.parseInt(badgeIconParam); + if (badgeIconType >= 0) { + nb.setBadgeIconType(badgeIconType); + } + } catch (Throwable t) { + // no-op + } + } + // Set badge count + String badgeCountParam = extras.getString(Constants.WZRK_BADGE_COUNT, null); + if (badgeCountParam != null) { + try { + int badgeCount = Integer.parseInt(badgeCountParam); + if (badgeCount >= 0) { + nb.setNumber(badgeCount); + } + } catch (Throwable t) { + // no-op + } + } + } + + private int generateNotificationId(int notificationId, Bundle extras) { // if we have no user set notificationID then try collapse key if (notificationId == Constants.EMPTY_NOTIFICATION_ID) { try { @@ -994,59 +1090,10 @@ private void triggerNotification(Context context, Bundle extras, int notificatio notificationId = (int) (Math.random() * 100); config.getLogger().debug(config.getAccountId(), "Setting random notificationId: " + notificationId); } + return notificationId; + } - NotificationCompat.Builder nb; - if (requiresChannelId) { - nb = new NotificationCompat.Builder(context, updatedChannelId); - - // choices here are Notification.BADGE_ICON_NONE = 0, Notification.BADGE_ICON_SMALL = 1, Notification.BADGE_ICON_LARGE = 2. Default is Notification.BADGE_ICON_LARGE - String badgeIconParam = extras - .getString(Constants.WZRK_BADGE_ICON, null); - if (badgeIconParam != null) { - try { - int badgeIconType = Integer.parseInt(badgeIconParam); - if (badgeIconType >= 0) { - nb.setBadgeIconType(badgeIconType); - } - } catch (Throwable t) { - // no-op - } - } - - String badgeCountParam = extras.getString(Constants.WZRK_BADGE_COUNT, null);//cbi - if (badgeCountParam != null) { - try { - int badgeCount = Integer.parseInt(badgeCountParam); - if (badgeCount >= 0) { - nb.setNumber(badgeCount); - } - } catch (Throwable t) { - // no-op - } - } - - } else { - // noinspection all - nb = new NotificationCompat.Builder(context); - } - - nb.setPriority(priorityInt); - - //remove sound for fallback notif - - if (iNotificationRenderer instanceof AudibleNotification) { - nb = ((AudibleNotification) iNotificationRenderer).setSound(context, extras, nb, config); - } - - nb = iNotificationRenderer.renderNotification(extras, context, nb, config, notificationId); - if (nb == null) {// template renderer can return null if template type is null - return; - } - - Notification n = nb.build(); - notificationManager.notify(notificationId, n); - config.getLogger().debug(config.getAccountId(), "Rendered notification: " + n.toString());//cb - + private void storePushNotification(Bundle extras) { String extrasFrom = extras.getString(Constants.EXTRAS_FROM); if (extrasFrom == null || !extrasFrom.equals("PTReceiver")) { String ttl = extras.getString(Constants.WZRK_TIME_TO_LIVE, diff --git a/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/PushTemplateNotificationHandler.java b/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/PushTemplateNotificationHandler.java index bcee4d0a9..9d61ff616 100644 --- a/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/PushTemplateNotificationHandler.java +++ b/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/PushTemplateNotificationHandler.java @@ -1,16 +1,32 @@ package com.clevertap.android.pushtemplates; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Bundle; + +import androidx.core.content.ContextCompat; + import com.clevertap.android.sdk.CleverTapAPI; import com.clevertap.android.sdk.CleverTapInstanceConfig; import com.clevertap.android.sdk.interfaces.ActionButtonClickHandler; -import com.clevertap.android.sdk.pushnotification.INotificationRenderer; import com.clevertap.android.sdk.pushnotification.PushNotificationUtil; + import java.util.Objects; public class PushTemplateNotificationHandler implements ActionButtonClickHandler { + public static boolean isServiceDeclared(Context context, String serviceClassName) { + try { + ComponentName componentName = new ComponentName(context.getPackageName(), serviceClassName); + context.getPackageManager().getServiceInfo(componentName, 0); + return true; + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + @Override public boolean onActionButtonClick(final Context context, final Bundle extras, final int notificationId) { String actionID = extras.getString(PTConstants.PT_ACTION_ID); @@ -34,13 +50,16 @@ public boolean onActionButtonClick(final Context context, final Bundle extras, f public boolean onMessageReceived(final Context applicationContext, final Bundle message, final String pushType) { try { PTLog.debug("Inside Push Templates"); - // initial setup - INotificationRenderer templateRenderer = new TemplateRenderer(applicationContext, message); - CleverTapAPI cleverTapAPI = CleverTapAPI - .getGlobalInstance(applicationContext, - PushNotificationUtil.getAccountIdFromNotificationBundle(message)); - Objects.requireNonNull(cleverTapAPI) - .renderPushNotificationOnCallerThread(templateRenderer, applicationContext, message); + + TemplateRenderer templateRenderer = new TemplateRenderer(applicationContext, message); + if (isServiceDeclared(applicationContext, "com.clevertap.android.pushtemplates.TimerService") && templateRenderer.getTemplateType() == TemplateType.TIMER) { + Intent serviceIntent = new Intent(applicationContext, TimerTemplateService.class); + serviceIntent.putExtras(message); + ContextCompat.startForegroundService(applicationContext, serviceIntent); + } else { + CleverTapAPI cleverTapAPI = CleverTapAPI.getGlobalInstance(applicationContext, PushNotificationUtil.getAccountIdFromNotificationBundle(message)); + Objects.requireNonNull(cleverTapAPI).renderPushNotificationOnCallerThread(templateRenderer, applicationContext, message); + } } catch (Throwable throwable) { PTLog.verbose("Error parsing FCM payload", throwable); @@ -52,5 +71,4 @@ public boolean onMessageReceived(final Context applicationContext, final Bundle public boolean onNewToken(final Context applicationContext, final String token, final String pushType) { return true; } - } \ No newline at end of file diff --git a/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TemplateRenderer.kt b/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TemplateRenderer.kt index 271f461a1..2e13ec486 100644 --- a/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TemplateRenderer.kt +++ b/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TemplateRenderer.kt @@ -13,7 +13,6 @@ import android.os.* import android.os.Build.VERSION import android.os.Build.VERSION_CODES import androidx.annotation.RequiresApi -import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat.Builder import com.clevertap.android.pushtemplates.content.FiveIconBigContentView import com.clevertap.android.pushtemplates.content.FiveIconSmallContentView @@ -109,10 +108,10 @@ class TemplateRenderer : INotificationRenderer, AudibleNotification { } override fun renderNotification( - extras: Bundle, context: Context, nb: NotificationCompat.Builder, + extras: Bundle, context: Context, nb: Builder, config: CleverTapInstanceConfig, notificationId: Int - ): NotificationCompat.Builder? { + ): Builder? { if (pt_id == null) { PTLog.verbose("Template ID not provided. Cannot create the notification") return null @@ -165,7 +164,7 @@ class TemplateRenderer : INotificationRenderer, AudibleNotification { if (ValidatorFactory.getValidator(TemplateType.ZERO_BEZEL, this)?.validate() == true) return ZeroBezelStyle(this).builderFromStyle(context, extras, notificationId, nb) - TemplateType.TIMER -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + TemplateType.TIMER -> if (VERSION.SDK_INT >= VERSION_CODES.N) { if (ValidatorFactory.getValidator(TemplateType.TIMER, this)?.validate() == true) { val timerEnd = getTimerEnd() if (timerEnd != null) { @@ -225,7 +224,11 @@ class TemplateRenderer : INotificationRenderer, AudibleNotification { return timer_end } - @RequiresApi(Build.VERSION_CODES.M) + fun getTemplateType() : TemplateType? { + return templateType + } + + @RequiresApi(VERSION_CODES.M) private fun timerRunner(context: Context, extras: Bundle, notificationId: Int, delay: Int?) { val handler = Handler(Looper.getMainLooper()) @@ -237,6 +240,8 @@ class TemplateRenderer : INotificationRenderer, AudibleNotification { notificationId ) && ValidatorFactory.getValidator(TemplateType.BASIC, this)?.validate() == true ) { + val intent = Intent(context, TimerTemplateService::class.java) + context.stopService(intent) val applicationContext = context.applicationContext val basicTemplateBundle = extras.clone() as Bundle basicTemplateBundle.remove("wzrk_rnv") diff --git a/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TemplateType.kt b/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TemplateType.kt index 45866918c..0a8e3081d 100644 --- a/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TemplateType.kt +++ b/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TemplateType.kt @@ -1,6 +1,6 @@ package com.clevertap.android.pushtemplates -internal enum class TemplateType(private val templateType: String) { +enum class TemplateType(private val templateType: String) { BASIC("pt_basic"), AUTO_CAROUSEL("pt_carousel"), MANUAL_CAROUSEL("pt_manual_carousel"), RATING("pt_rating"), FIVE_ICONS("pt_five_icons"), PRODUCT_DISPLAY("pt_product_display"), diff --git a/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TimerTemplateService.kt b/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TimerTemplateService.kt new file mode 100644 index 000000000..64b55930f --- /dev/null +++ b/clevertap-pushtemplates/src/main/java/com/clevertap/android/pushtemplates/TimerTemplateService.kt @@ -0,0 +1,58 @@ +package com.clevertap.android.pushtemplates + +import android.annotation.SuppressLint +import android.app.Service +import android.content.Intent +import android.os.Handler +import android.os.IBinder +import android.os.Looper +import androidx.core.app.NotificationCompat +import com.clevertap.android.sdk.CleverTapAPI +import com.clevertap.android.sdk.CleverTapInstanceConfig +import com.clevertap.android.sdk.pushnotification.PushNotificationUtil +import com.clevertap.android.sdk.task.CTExecutorFactory + + +class TimerTemplateService : Service() { + + @SuppressLint("WrongConstant") + override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { + val message = intent.extras!! + val templateRenderer = TemplateRenderer(this@TimerTemplateService, message) + + val cleverTapAPI = CleverTapAPI.getGlobalInstance( + this@TimerTemplateService, + PushNotificationUtil.getAccountIdFromNotificationBundle(message) + ) + val config: CleverTapInstanceConfig? = cleverTapAPI?.coreState?.config + + config.let { + val task = CTExecutorFactory.executors(config).postAsyncSafelyTask() + task.execute("TimerTemplateService") { + try { + + val notificationBuilder = cleverTapAPI?.getPushNotificationOnCallerThread( + templateRenderer, this@TimerTemplateService, message + ) + + notificationBuilder?.let { + it.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE) + val nb = it.build() + Handler(Looper.getMainLooper()).post { + startForeground(templateRenderer.notificationId, nb) + } + } + } catch (e: Exception) { + e.printStackTrace() + } + null + } + + return super.onStartCommand(intent, flags, startId) + } + } + + override fun onBind(intent: Intent): IBinder? { + return null + } +} diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index aea65b6f4..d9e8c35a1 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -105,6 +105,11 @@ + +