Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve push click behavior #247

Merged
merged 16 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions messagingpush/api/messagingpush.api
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ public final class io/customer/messagingpush/CustomerIOFirebaseMessagingService$

public final class io/customer/messagingpush/MessagingPushModuleConfig : io/customer/sdk/module/CustomerIOModuleConfig {
public static final field Companion Lio/customer/messagingpush/MessagingPushModuleConfig$Companion;
public synthetic fun <init> (ZLio/customer/messagingpush/data/communication/CustomerIOPushNotificationCallback;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (ZLio/customer/messagingpush/data/communication/CustomerIOPushNotificationCallback;ZLio/customer/messagingpush/config/PushClickBehavior;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getAutoTrackPushEvents ()Z
public final fun getNotificationCallback ()Lio/customer/messagingpush/data/communication/CustomerIOPushNotificationCallback;
public final fun getPushClickBehavior ()Lio/customer/messagingpush/config/PushClickBehavior;
public final fun getRedirectDeepLinksToOtherApps ()Z
}

Expand All @@ -38,6 +39,7 @@ public final class io/customer/messagingpush/MessagingPushModuleConfig$Builder :
public synthetic fun build ()Lio/customer/sdk/module/CustomerIOModuleConfig;
public final fun setAutoTrackPushEvents (Z)Lio/customer/messagingpush/MessagingPushModuleConfig$Builder;
public final fun setNotificationCallback (Lio/customer/messagingpush/data/communication/CustomerIOPushNotificationCallback;)Lio/customer/messagingpush/MessagingPushModuleConfig$Builder;
public final fun setPushClickBehavior (Lio/customer/messagingpush/config/PushClickBehavior;)Lio/customer/messagingpush/MessagingPushModuleConfig$Builder;
public final fun setRedirectDeepLinksToOtherApps (Z)Lio/customer/messagingpush/MessagingPushModuleConfig$Builder;
}

Expand All @@ -58,6 +60,25 @@ public final class io/customer/messagingpush/ModuleMessagingPushFCM : io/custome
public final class io/customer/messagingpush/ModuleMessagingPushFCM$Companion {
}

public final class io/customer/messagingpush/activity/NotificationClickReceiverActivity : android/app/Activity, io/customer/sdk/tracking/TrackableScreen {
public static final field Companion Lio/customer/messagingpush/activity/NotificationClickReceiverActivity$Companion;
public static final field NOTIFICATION_PAYLOAD_EXTRA Ljava/lang/String;
public fun <init> ()V
public final fun getLogger ()Lio/customer/sdk/util/Logger;
public fun getScreenName ()Ljava/lang/String;
}

public final class io/customer/messagingpush/activity/NotificationClickReceiverActivity$Companion {
}

public final class io/customer/messagingpush/config/PushClickBehavior : java/lang/Enum {
public static final field ACTIVITY_NO_FLAGS Lio/customer/messagingpush/config/PushClickBehavior;
public static final field ACTIVITY_PREVENT_RESTART Lio/customer/messagingpush/config/PushClickBehavior;
public static final field RESET_TASK_STACK Lio/customer/messagingpush/config/PushClickBehavior;
public static fun valueOf (Ljava/lang/String;)Lio/customer/messagingpush/config/PushClickBehavior;
public static fun values ()[Lio/customer/messagingpush/config/PushClickBehavior;
}

public abstract interface class io/customer/messagingpush/data/communication/CustomerIOPushNotificationCallback {
public abstract fun createTaskStackFromPayload (Landroid/content/Context;Lio/customer/messagingpush/data/model/CustomerIOParsedPushPayload;)Landroidx/core/app/TaskStackBuilder;
public abstract fun onNotificationComposed (Lio/customer/messagingpush/data/model/CustomerIOParsedPushPayload;Landroidx/core/app/NotificationCompat$Builder;)V
Expand Down Expand Up @@ -116,16 +137,16 @@ public final class io/customer/messagingpush/provider/FCMTokenProviderImpl : io/
}

public abstract interface class io/customer/messagingpush/util/DeepLinkUtil {
public abstract fun createDeepLinkExternalIntent (Landroid/content/Context;Ljava/lang/String;Z)Landroid/content/Intent;
public abstract fun createDeepLinkExternalIntent (Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;
public abstract fun createDeepLinkHostAppIntent (Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;
public abstract fun createDefaultHostAppIntent (Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;
public abstract fun createDefaultHostAppIntent (Landroid/content/Context;)Landroid/content/Intent;
}

public final class io/customer/messagingpush/util/DeepLinkUtilImpl : io/customer/messagingpush/util/DeepLinkUtil {
public fun <init> (Lio/customer/sdk/util/Logger;Lio/customer/messagingpush/MessagingPushModuleConfig;)V
public fun createDeepLinkExternalIntent (Landroid/content/Context;Ljava/lang/String;Z)Landroid/content/Intent;
public fun createDeepLinkExternalIntent (Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;
public fun createDeepLinkHostAppIntent (Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;
public fun createDefaultHostAppIntent (Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;
public fun createDefaultHostAppIntent (Landroid/content/Context;)Landroid/content/Intent;
}

public abstract interface class io/customer/messagingpush/util/PushTrackingUtil {
Expand Down
26 changes: 18 additions & 8 deletions messagingpush/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@
<uses-permission android:name="android.permission.INTERNET" />

<application>
<!-- Transparent activity for push interactions

Notes:
* Using launchMode="singleTask" because Android OS does not launch activity again in one session, if the activity
was launched recently from earlier notification.
* launchMode="singleTop" does not work well with ACTIVITY_NO_FLAGS if customer app also has launchMode="singleTop"
(e.g. Flutter apps) and have multiple instances launched from notifications in one session.

-->
<activity
android:name=".activity.NotificationClickReceiverActivity"
android:excludeFromRecents="true"
android:exported="true"
android:launchMode="singleTask"
android:noHistory="true"
android:taskAffinity=""
android:theme="@android:style/Theme.Translucent.NoTitleBar" />

<service
android:name=".CustomerIOFirebaseMessagingService"
android:exported="false">
Expand All @@ -14,14 +32,6 @@
</intent-filter>
</service>

<!-- Action receiver for push interactions -->
<receiver
android:name=".CustomerIOPushReceiver"
android:exported="false">
<intent-filter>
<action android:name="io.customer.messagingpush.PUSH_ACTION" />
</intent-filter>
</receiver>
<!--
Broadcast receiver for listening to push events from GoogleCloudMessaging (GCM). The receiver
listens to message broadcast emitted by Google Cloud APIs. Read class docs for more details.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@
import android.os.Bundle
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.annotation.VisibleForTesting
import androidx.core.app.NotificationCompat
import androidx.core.app.TaskStackBuilder
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import io.customer.messagingpush.activity.NotificationClickReceiverActivity
import io.customer.messagingpush.data.model.CustomerIOParsedPushPayload
import io.customer.messagingpush.di.deepLinkUtil
import io.customer.messagingpush.di.moduleConfig
import io.customer.messagingpush.extensions.*
import io.customer.messagingpush.processor.PushMessageProcessor
import io.customer.messagingpush.util.DeepLinkUtil
import io.customer.messagingpush.util.PushTrackingUtil.Companion.DELIVERY_ID_KEY
import io.customer.messagingpush.util.PushTrackingUtil.Companion.DELIVERY_TOKEN_KEY
import io.customer.sdk.CustomerIO
Expand Down Expand Up @@ -70,9 +69,6 @@
private val moduleConfig: MessagingPushModuleConfig
get() = diGraph.moduleConfig

private val deepLinkUtil: DeepLinkUtil
get() = diGraph.deepLinkUtil

private val bundle: Bundle by lazy {
Bundle().apply {
remoteMessage.data.forEach { entry ->
Expand Down Expand Up @@ -129,7 +125,7 @@
bundle.putInt(NOTIFICATION_REQUEST_CODE, requestCode)

val applicationInfo = try {
context.packageManager.getApplicationInfo(

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / API check

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / Android Lint (messagingpush)

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / Android Lint (messagingpush)

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / Unit tests (messagingpush)

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / Unit tests (messagingpush)

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / API check

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / instrumentation-test (java_layout)

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / instrumentation-test (java_layout)

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / instrumentation-test (kotlin_compose)

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java

Check warning on line 128 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View workflow job for this annotation

GitHub Actions / instrumentation-test (kotlin_compose)

'getApplicationInfo(String, Int): ApplicationInfo' is deprecated. Deprecated in Java
context.packageName,
PackageManager.GET_META_DATA
)
Expand Down Expand Up @@ -210,61 +206,38 @@
payload = payload,
builder = notificationBuilder
)
createIntentFromLink(
createIntentForNotificationClick(

Check warning on line 209 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View check run for this annotation

Codecov / codecov/patch

messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt#L209

Added line #L209 was not covered by tests
context,
requestCode,
payload
)?.let { pendingIntent ->
).let { pendingIntent ->

Check warning on line 213 in messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt

View check run for this annotation

Codecov / codecov/patch

messagingpush/src/main/java/io/customer/messagingpush/CustomerIOPushNotificationHandler.kt#L213

Added line #L213 was not covered by tests
notificationBuilder.setContentIntent(pendingIntent)
}

val notification = notificationBuilder.build()
notificationManager.notify(requestCode, notification)
}

private fun createIntentFromLink(
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun createIntentForNotificationClick(
context: Context,
requestCode: Int,
payload: CustomerIOParsedPushPayload
): PendingIntent? {
// In Android 12, you must specify the mutability of each PendingIntent
): PendingIntent {
val notifyIntent = Intent(context, NotificationClickReceiverActivity::class.java)
notifyIntent.putExtra(NotificationClickReceiverActivity.NOTIFICATION_PAYLOAD_EXTRA, payload)
// In Android M, you must specify the mutability of each PendingIntent
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}

if (context.applicationInfo.targetSdkVersion > Build.VERSION_CODES.R) {
val taskStackBuilder = moduleConfig.notificationCallback?.createTaskStackFromPayload(
context,
payload
) ?: kotlin.run {
val pushContentIntent: Intent? = deepLinkUtil.createDeepLinkHostAppIntent(
context,
payload.deepLink
) ?: deepLinkUtil.createDefaultHostAppIntent(context, payload.deepLink)
pushContentIntent?.putExtras(bundle)

return@run pushContentIntent?.let { intent ->
TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(intent)
}
}
}

return taskStackBuilder?.getPendingIntent(requestCode, flags)
} else {
val pushContentIntent = Intent(CustomerIOPushReceiver.ACTION)
pushContentIntent.setClass(context, CustomerIOPushReceiver::class.java)

pushContentIntent.putExtra(CustomerIOPushReceiver.PUSH_PAYLOAD_KEY, payload)
return PendingIntent.getBroadcast(
context,
requestCode,
pushContentIntent,
flags
)
}
return PendingIntent.getActivity(
context,
requestCode,
notifyIntent,
flags
)
}

private fun addImage(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
package io.customer.messagingpush

import io.customer.messagingpush.config.PushClickBehavior
import io.customer.messagingpush.config.PushClickBehavior.ACTIVITY_PREVENT_RESTART
import io.customer.messagingpush.data.communication.CustomerIOPushNotificationCallback
import io.customer.sdk.module.CustomerIOModuleConfig

/**
* Push messaging module configurations
* <p/>
* Please note for apps targeting Android 12 or greater, all other apps and
* browser intents will be opened over host app so that notification metrics
* are not affected
*
* @property notificationCallback callback to override default sdk behaviour for
* notifications
* @property redirectDeepLinksToOtherApps flag to support opening urls from
* notification to other native apps or browsers; default true
* @property pushClickBehavior defines the behavior when a push notification
* is clicked
*/
class MessagingPushModuleConfig private constructor(
val autoTrackPushEvents: Boolean,
val notificationCallback: CustomerIOPushNotificationCallback?,
val redirectDeepLinksToOtherApps: Boolean
val redirectDeepLinksToOtherApps: Boolean,
val pushClickBehavior: PushClickBehavior
) : CustomerIOModuleConfig {
class Builder : CustomerIOModuleConfig.Builder<MessagingPushModuleConfig> {
private var autoTrackPushEvents: Boolean = true
private var notificationCallback: CustomerIOPushNotificationCallback? = null
private var redirectDeepLinksToOtherApps: Boolean = true
private var pushClickBehavior: PushClickBehavior = ACTIVITY_PREVENT_RESTART

/**
* Allows to enable/disable automatic tracking of push events. Auto tracking will generate
Expand Down Expand Up @@ -62,11 +64,23 @@ class MessagingPushModuleConfig private constructor(
return this
}

/**
* Defines the behavior when a notification is clicked.
*
* @param pushClickBehavior the behavior when a notification is clicked; default [PushClickBehavior.ACTIVITY_PREVENT_RESTART].
* @see PushClickBehavior for more details.
*/
fun setPushClickBehavior(pushClickBehavior: PushClickBehavior): Builder {
this.pushClickBehavior = pushClickBehavior
return this
}

override fun build(): MessagingPushModuleConfig {
return MessagingPushModuleConfig(
autoTrackPushEvents = autoTrackPushEvents,
notificationCallback = notificationCallback,
redirectDeepLinksToOtherApps = redirectDeepLinksToOtherApps
redirectDeepLinksToOtherApps = redirectDeepLinksToOtherApps,
pushClickBehavior = pushClickBehavior
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package io.customer.messagingpush

import androidx.annotation.VisibleForTesting
import io.customer.base.internal.InternalCustomerIOApi
import io.customer.messagingpush.di.deepLinkUtil
import io.customer.messagingpush.di.fcmTokenProvider
import io.customer.messagingpush.di.pushTrackingUtil
import io.customer.messagingpush.lifecycle.MessagingPushLifecycleCallback
Expand Down Expand Up @@ -41,7 +40,6 @@ internal constructor(
diGraph.activityLifecycleCallbacks.registerCallback(
MessagingPushLifecycleCallback(
moduleConfig = moduleConfig,
deepLinkUtil = diGraph.deepLinkUtil,
pushTrackingUtil = diGraph.pushTrackingUtil
)
)
Expand Down
Loading
Loading