From c993718d2f2fb06c487e58cafe1e30b156e71e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Herculano?= Date: Fri, 25 Jul 2025 12:43:11 +0200 Subject: [PATCH 1/7] implement onUserInactive callback --- cmplibrary/src/main/assets/js_receiver.js | 4 ++++ .../src/main/java/com/sourcepoint/cmplibrary/SpClient.kt | 5 +++++ .../sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/cmplibrary/src/main/assets/js_receiver.js b/cmplibrary/src/main/assets/js_receiver.js index e5208ec20..0c2a3d1cb 100644 --- a/cmplibrary/src/main/assets/js_receiver.js +++ b/cmplibrary/src/main/assets/js_receiver.js @@ -62,6 +62,7 @@ function handleEvent(event) { onAction: notImplemented('onAction'), onError: notImplemented('onError'), log: notImplemented('log'), + onUserInactive: notImplemented('onUserInactive'), }; try { switch (payload.name) { @@ -82,6 +83,9 @@ function handleEvent(event) { case 'sp.readyForPreloadConsent': sdk.readyForConsentPreload(); break; + case 'sp.userInactive': + sdk.onUserInactive(); + break; default: sdk.log("Unexpected event name: " + JSON.stringify(payload)); } diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt index 66a583895..93f546488 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt @@ -35,6 +35,11 @@ interface SpClient { * This callback is invoked if no activity could open an intent with the given url. */ fun onNoIntentActivitiesFound(url: String) + + /** + * This callback is invoked when the user becomes inactive in the rendering app. + */ + fun onUserInactive() } interface UnitySpClient : SpClient { diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt index f261a885a..2045552b0 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt @@ -12,6 +12,7 @@ import android.view.View import android.webkit.JavascriptInterface import android.webkit.WebChromeClient import android.webkit.WebView +import com.sourcepoint.cmplibrary.SpClient import com.sourcepoint.cmplibrary.data.network.util.CampaignType import com.sourcepoint.cmplibrary.exception.ConsentLibExceptionK import com.sourcepoint.cmplibrary.exception.NoIntentFoundForUrl @@ -81,6 +82,7 @@ interface SPWebMessageUIClient : SPMessageUIClient { fun onAction(actionData: String) fun log(message: String) fun onError(error: String) + fun onUserInactive() } @SuppressLint("ViewConstructor", "SetJavaScriptEnabled") @@ -355,4 +357,9 @@ class SPConsentWebView( @JavascriptInterface override fun log(message: String) = println(message) + + @JavascriptInterface + override fun onUserInactive() = runOnMain { + (messageUIClient as? SpClient)?.onUserInactive() + } } From 6f1ca2d0ac8e71e5e1bd139104242d215d0a5288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Herculano?= Date: Mon, 28 Jul 2025 15:05:44 +0200 Subject: [PATCH 2/7] rename onUserInactive to onMessageInactivityTimeout --- cmplibrary/src/main/assets/js_receiver.js | 4 ++-- .../src/main/java/com/sourcepoint/cmplibrary/SpClient.kt | 2 +- .../sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmplibrary/src/main/assets/js_receiver.js b/cmplibrary/src/main/assets/js_receiver.js index 0c2a3d1cb..8bfbec973 100644 --- a/cmplibrary/src/main/assets/js_receiver.js +++ b/cmplibrary/src/main/assets/js_receiver.js @@ -62,7 +62,7 @@ function handleEvent(event) { onAction: notImplemented('onAction'), onError: notImplemented('onError'), log: notImplemented('log'), - onUserInactive: notImplemented('onUserInactive'), + onMessageInactivityTimeout: notImplemented('onMessageInactivityTimeout'), }; try { switch (payload.name) { @@ -84,7 +84,7 @@ function handleEvent(event) { sdk.readyForConsentPreload(); break; case 'sp.userInactive': - sdk.onUserInactive(); + sdk.onMessageInactivityTimeout(); break; default: sdk.log("Unexpected event name: " + JSON.stringify(payload)); diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt index 93f546488..1376731e3 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt @@ -39,7 +39,7 @@ interface SpClient { /** * This callback is invoked when the user becomes inactive in the rendering app. */ - fun onUserInactive() + fun onMessageInactivityTimeout() } interface UnitySpClient : SpClient { diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt index 2045552b0..7c2298afa 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt @@ -82,7 +82,7 @@ interface SPWebMessageUIClient : SPMessageUIClient { fun onAction(actionData: String) fun log(message: String) fun onError(error: String) - fun onUserInactive() + fun onMessageInactivityTimeout() } @SuppressLint("ViewConstructor", "SetJavaScriptEnabled") @@ -359,7 +359,7 @@ class SPConsentWebView( override fun log(message: String) = println(message) @JavascriptInterface - override fun onUserInactive() = runOnMain { - (messageUIClient as? SpClient)?.onUserInactive() + override fun onMessageInactivityTimeout() = runOnMain { + (messageUIClient as? SpClient)?.onMessageInactivityTimeout() } } From a4d4ee7b69d0642c187ab7d69697fe0bae86c44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Herculano?= Date: Mon, 28 Jul 2025 15:13:25 +0200 Subject: [PATCH 3/7] Update README.md --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3c84707ea..4e41a4894 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,7 @@ Kotlin override fun onConsentReady(consent: SPConsents) { } override fun onAction(view: View, consentAction: ConsentAction): ConsentAction = consentAction override fun onNoIntentActivitiesFound(url: String) {} + override fun onMessageInactivityTimeout() { } override fun onSpFinished(sPConsents: SPConsents) { } } ``` @@ -200,6 +201,9 @@ Java spConsentLib.showView(v); } + @Override + public void onMessageInactivityTimeout() { } + @Override public void onSpFinished(@NotNull SPConsents sPConsents) { } } @@ -213,17 +217,18 @@ Meaning of the callbacks : - `onError`: the client has access to the error details. [See `onError` codes](#onerror-codes) - `onUIReady`: the consent view should be inflated; - `onAction`: the client receives the selected action type and has the chance to set the `pubData` fields; +- `onMessageInactivityTimeout`: called when the user becomes inactive while viewing a consent message; - `onSpFinished`: there is nothing to process, all the work is done. Some of the above callbacks work on the main thread while others are work on a worker thread. Please see the table below for the distinction: | Main thread | Worker thread | | ---------------------- | -------------- | -| `onUIReady` | `onSpFinished` | -| `onError` | `onAction` | -| `onConsentReady` | | -| `onNativeMessageReady` | | -| `onUIFinished` | | +| `onUIReady` | `onSpFinished` | +| `onError` | `onAction` | +| `onConsentReady` | `onMessageInactivityTimeout` | +| `onNativeMessageReady` | | +| `onUIFinished` | | ### onError codes From 84863e706976753eac075b9d56e33dfd93f24ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Herculano?= Date: Wed, 30 Jul 2025 18:08:57 +0200 Subject: [PATCH 4/7] add default implementation to optional callbacks from SpClient --- .../src/main/java/com/sourcepoint/cmplibrary/SpClient.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt index 1376731e3..8b92ee40e 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpClient.kt @@ -16,10 +16,10 @@ interface SpClient { /** * It is invoked when the message is available to the client App */ - fun onNativeMessageReady(message: MessageStructure, messageController: NativeMessageController) + fun onNativeMessageReady(message: MessageStructure, messageController: NativeMessageController) {} @Deprecated("onMessageReady callback will be removed in favor of onMessageReady(message: MessageStructure, messageController: NativeMessageController). Currently this callback is disabled.") - fun onMessageReady(message: JSONObject) + fun onMessageReady(message: JSONObject) {} fun onAction(view: View, consentAction: ConsentAction): ConsentAction fun onUIFinished(view: View) @@ -39,7 +39,7 @@ interface SpClient { /** * This callback is invoked when the user becomes inactive in the rendering app. */ - fun onMessageInactivityTimeout() + fun onMessageInactivityTimeout() {} } interface UnitySpClient : SpClient { From 4de51c5e3e06813df4c1cbf7cddfedfa72b7fed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Herculano?= Date: Wed, 30 Jul 2025 18:09:18 +0200 Subject: [PATCH 5/7] implement onMessageInactivityTimeout on sample app java activity --- .../main/java/com/sourcepoint/app/v6/MainActivityJava.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/app/src/main/java/com/sourcepoint/app/v6/MainActivityJava.java b/samples/app/src/main/java/com/sourcepoint/app/v6/MainActivityJava.java index f6b7b6d49..ab183b3f6 100644 --- a/samples/app/src/main/java/com/sourcepoint/app/v6/MainActivityJava.java +++ b/samples/app/src/main/java/com/sourcepoint/app/v6/MainActivityJava.java @@ -100,7 +100,6 @@ protected void onDestroy() { } class LocalClient implements SpClient { - @Override public void onConsentReady(@NotNull SPConsents consent) { Map grants = consent.getGdpr().getConsent().getGrants(); @@ -149,6 +148,8 @@ public void onSpFinished(@NotNull SPConsents sPConsents) { public void onNoIntentActivitiesFound(@NotNull String url) { } - } + @Override + public void onMessageInactivityTimeout() {} + } } From f5c8d4808932184c935134a4b9c9a20a91ef555e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Herculano?= Date: Wed, 30 Jul 2025 18:10:15 +0200 Subject: [PATCH 6/7] remove native message related code from NativeMessage --- .../sourcepoint/app/v6/MainActivityKotlin.kt | 134 ------------------ 1 file changed, 134 deletions(-) diff --git a/samples/app/src/main/java/com/sourcepoint/app/v6/MainActivityKotlin.kt b/samples/app/src/main/java/com/sourcepoint/app/v6/MainActivityKotlin.kt index 8ff64e4f0..2425c14c3 100644 --- a/samples/app/src/main/java/com/sourcepoint/app/v6/MainActivityKotlin.kt +++ b/samples/app/src/main/java/com/sourcepoint/app/v6/MainActivityKotlin.kt @@ -4,26 +4,18 @@ import android.content.Intent import android.content.SharedPreferences import android.os.Bundle import android.preference.PreferenceManager -import android.text.method.ScrollingMovementMethod import android.util.Log import android.view.View import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity -import androidx.core.graphics.toColorInt import com.sourcepoint.app.v6.core.DataProvider import com.sourcepoint.app.v6.databinding.ActivityMainV7Binding -import com.sourcepoint.app.v6.databinding.NativeMessageBinding -import com.sourcepoint.cmplibrary.NativeMessageController import com.sourcepoint.cmplibrary.SpClient -import com.sourcepoint.cmplibrary.core.nativemessage.MessageStructure -import com.sourcepoint.cmplibrary.core.nativemessage.NativeAction -import com.sourcepoint.cmplibrary.core.nativemessage.NativeComponent import com.sourcepoint.cmplibrary.creation.delegate.spConsentLibLazy import com.sourcepoint.cmplibrary.data.network.connection.ConnectionManager import com.sourcepoint.cmplibrary.data.network.util.CampaignType import com.sourcepoint.cmplibrary.model.ConsentAction import com.sourcepoint.cmplibrary.model.PMTab -import com.sourcepoint.cmplibrary.model.exposed.NativeMessageActionType import com.sourcepoint.cmplibrary.model.exposed.SPConsents import org.json.JSONObject import org.koin.android.ext.android.inject @@ -38,7 +30,6 @@ class MainActivityKotlin : AppCompatActivity() { } private lateinit var binding: ActivityMainV7Binding - private lateinit var nativeMessageBinding: NativeMessageBinding private val dataProvider by inject() private val spClientObserver: List by inject() @@ -136,17 +127,6 @@ class MainActivityKotlin : AppCompatActivity() { } internal inner class LocalClient : SpClient { - override fun onNativeMessageReady( - message: MessageStructure, - messageController: NativeMessageController - ) { - setNativeMessage(message, messageController) - } - - @Deprecated("onMessageReady callback will be removed in favor of onUIReady. Currently this callback is disabled.") - override fun onMessageReady(message: JSONObject) { - } - override fun onError(error: Throwable) { spClientObserver.forEach { it.onError(error) } error.printStackTrace() @@ -195,120 +175,6 @@ class MainActivityKotlin : AppCompatActivity() { } } - fun setNativeMessage(message: MessageStructure, messageController: NativeMessageController) { - nativeMessageBinding = NativeMessageBinding.inflate(layoutInflater, null, false) - nativeMessageBinding.run { - message.messageComponents?.let { - setTitle(it.title ?: throw RuntimeException()) - setBody(it.body ?: throw RuntimeException()) - setAgreeBtn(it.body ?: throw RuntimeException()) - it.actions.forEach { a -> - when (a.choiceType) { - NativeMessageActionType.REJECT_ALL -> setRejectAllBtn(a) - NativeMessageActionType.ACCEPT_ALL -> setAcceptAllBtn(a) - NativeMessageActionType.MSG_CANCEL -> setCancelBtn(a) - NativeMessageActionType.SHOW_OPTIONS -> setOptionBtn(a) - else -> {} - } - } - } - acceptAll.setOnClickListener { - messageController.run { - removeNativeView(nativeMessageBinding.root) - sendConsent(NativeMessageActionType.ACCEPT_ALL, message.campaignType) - } - } - cancel.setOnClickListener { - messageController.run { - removeNativeView(nativeMessageBinding.root) - sendConsent(NativeMessageActionType.MSG_CANCEL, message.campaignType) - } - } - rejectAll.setOnClickListener { - messageController.run { - removeNativeView(nativeMessageBinding.root) - sendConsent(NativeMessageActionType.REJECT_ALL, message.campaignType) - } - } - showOptionsBtn.setOnClickListener { - messageController.run { - removeNativeView(nativeMessageBinding.root) - when (message.campaignType) { - CampaignType.GDPR -> dataProvider.gdprPmId - CampaignType.CCPA -> dataProvider.ccpaPmId - CampaignType.GLOBALCMP, CampaignType.PREFERENCES, CampaignType.USNAT, CampaignType.UNKNOWN -> throw RuntimeException() - }.let { pmId -> - messageController.showOptionNativeMessage(message.campaignType, pmId) - } - } - } - } - messageController.showNativeView(nativeMessageBinding.root) - } - - private fun setTitle(t: NativeComponent) { - nativeMessageBinding.titleNm.run { - text = t.text ?: "" - setBackgroundColor(t.style?.backgroundColor?.toColorInt() ?: throw RuntimeException()) - setTextColor(t.style?.color?.toColorInt() ?: throw RuntimeException()) - textSize = t.style?.fontSize ?: 10F - } - } - - private fun setBody(t: NativeComponent) { - nativeMessageBinding.bodyNm.run { - text = t.text ?: "" - setBackgroundColor(t.style?.backgroundColor?.toColorInt() ?: throw RuntimeException()) - setTextColor(t.style?.color?.toColorInt() ?: throw RuntimeException()) - textSize = t.style?.fontSize ?: 10F - movementMethod = ScrollingMovementMethod() - } - } - - private fun setAgreeBtn(t: NativeComponent) { - nativeMessageBinding.bodyNm.run { - text = t.text ?: "" - setBackgroundColor(t.style?.backgroundColor?.toColorInt() ?: throw RuntimeException()) - setTextColor(t.style?.color?.toColorInt() ?: throw RuntimeException()) - } - } - - private fun setCancelBtn(na: NativeAction) { - nativeMessageBinding.cancel.run { - text = na.text - setBackgroundColor(na.style.backgroundColor.toColorInt()) - setTextColor(na.style.color?.toColorInt() ?: throw RuntimeException()) - textSize = na.style.fontSize - } - } - - private fun setOptionBtn(na: NativeAction) { - nativeMessageBinding.showOptionsBtn.run { - text = na.text - setBackgroundColor(na.style.backgroundColor.toColorInt()) - setTextColor(na.style.color?.toColorInt() ?: throw RuntimeException()) - textSize = na.style.fontSize - } - } - - private fun setRejectAllBtn(na: NativeAction) { - nativeMessageBinding.rejectAll.run { - text = na.text - setBackgroundColor(na.style.backgroundColor.toColorInt()) - setTextColor(na.style.color?.toColorInt() ?: throw RuntimeException()) - textSize = na.style.fontSize - } - } - - private fun setAcceptAllBtn(na: NativeAction) { - nativeMessageBinding.acceptAll.run { - text = na.text - setBackgroundColor(na.style.backgroundColor.toColorInt()) - setTextColor(na.style.color?.toColorInt() ?: throw RuntimeException()) - textSize = na.style.fontSize - } - } - private fun addOldV6Consent() { val v6LocalState = JSONObject(consent) val spEditor = preferences.edit() From b2015c97e0e4089acbd1fcddab1cd3823acb68b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Herculano?= Date: Thu, 31 Jul 2025 21:56:48 +0200 Subject: [PATCH 7/7] add onMessageInactivityTimeout to SPMessageUIClient --- .../java/com/sourcepoint/cmplibrary/SpConsentLibMobileCore.kt | 4 ++++ .../sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpConsentLibMobileCore.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpConsentLibMobileCore.kt index 9426e8d7e..0589fbf46 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpConsentLibMobileCore.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/SpConsentLibMobileCore.kt @@ -385,4 +385,8 @@ class SpConsentLibMobileCore( runOnMain { spClient.onUIFinished(view) } renderNextMessageIfAny() } + + override fun onMessageInactivityTimeout() { + runOnMain { spClient.onMessageInactivityTimeout() } + } } diff --git a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt index 7c2298afa..24e236b45 100644 --- a/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt +++ b/cmplibrary/src/main/java/com/sourcepoint/cmplibrary/mobile_core/SPConsentWebView.kt @@ -46,6 +46,7 @@ interface SPMessageUIClient { fun onAction(view: View, action: ConsentAction) fun onError(error: ConsentLibExceptionK) fun finished(view: View) + fun onMessageInactivityTimeout() } interface SPMessageUI { @@ -82,7 +83,6 @@ interface SPWebMessageUIClient : SPMessageUIClient { fun onAction(actionData: String) fun log(message: String) fun onError(error: String) - fun onMessageInactivityTimeout() } @SuppressLint("ViewConstructor", "SetJavaScriptEnabled") @@ -360,6 +360,6 @@ class SPConsentWebView( @JavascriptInterface override fun onMessageInactivityTimeout() = runOnMain { - (messageUIClient as? SpClient)?.onMessageInactivityTimeout() + messageUIClient.onMessageInactivityTimeout() } }