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 diff --git a/cmplibrary/src/main/assets/js_receiver.js b/cmplibrary/src/main/assets/js_receiver.js index e5208ec20..8bfbec973 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'), + onMessageInactivityTimeout: notImplemented('onMessageInactivityTimeout'), }; try { switch (payload.name) { @@ -82,6 +83,9 @@ function handleEvent(event) { case 'sp.readyForPreloadConsent': sdk.readyForConsentPreload(); break; + case 'sp.userInactive': + 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 66a583895..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) @@ -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 onMessageInactivityTimeout() {} } interface UnitySpClient : SpClient { 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 f261a885a..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 @@ -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 @@ -45,6 +46,7 @@ interface SPMessageUIClient { fun onAction(view: View, action: ConsentAction) fun onError(error: ConsentLibExceptionK) fun finished(view: View) + fun onMessageInactivityTimeout() } interface SPMessageUI { @@ -355,4 +357,9 @@ class SPConsentWebView( @JavascriptInterface override fun log(message: String) = println(message) + + @JavascriptInterface + override fun onMessageInactivityTimeout() = runOnMain { + messageUIClient.onMessageInactivityTimeout() + } } 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() {} + } } 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()