package com.tinivo.rewardedads import android.app.Activity import android.util.Log import com.cocos.lib.CocosHelper import com.cocos.lib.JsbBridgeWrapper import com.google.android.ump.ConsentForm import com.google.android.ump.ConsentInformation import com.google.android.ump.ConsentRequestParameters import com.google.android.ump.FormError import com.google.android.ump.UserMessagingPlatform import org.json.JSONObject class PrivacyConsentBridge( private val activity: Activity, ) : JsbBridgeWrapper.OnScriptEventListener { companion object { private const val LOG_TAG = "RewardedAds" private const val REQUEST_EVENT = "tinivo.privacy.request" private const val RESPONSE_EVENT = "tinivo.privacy.response" } private val consentInformation: ConsentInformation by lazy { UserMessagingPlatform.getConsentInformation(activity) } private var installed = false private var didCompleteConsentInfoUpdate = false fun install() { if (installed) { return } installed = true requestConsentInfoUpdate() JsbBridgeWrapper.getInstance().addScriptEventListener(REQUEST_EVENT, this) } override fun onScriptEvent(arg: String?) { val payload = safePayload(arg) val requestId = payload?.optString("requestId").orEmpty() when (payload?.optString("command").orEmpty()) { "getState" -> dispatchState(requestId) "showOptions" -> showPrivacyOptions(requestId) else -> dispatchError(requestId, "unknown", "Unknown privacy command") } } private fun requestConsentInfoUpdate() { val parameters = ConsentRequestParameters.Builder().build() consentInformation.requestConsentInfoUpdate( activity, parameters, { didCompleteConsentInfoUpdate = true Log.d( LOG_TAG, "[RewardedAds][Privacy] consent info updated status=${consentInformation.consentStatus} privacyOptionsRequirementStatus=${consentInformation.privacyOptionsRequirementStatus}", ) UserMessagingPlatform.loadAndShowConsentFormIfRequired(activity) { formError -> if (formError != null) { Log.w( LOG_TAG, "[RewardedAds][Privacy] consent form failed code=${formError.errorCode} message=${formError.message.orEmpty()}", ) return@loadAndShowConsentFormIfRequired } Log.d(LOG_TAG, "[RewardedAds][Privacy] consent form completed") } }, { requestError -> didCompleteConsentInfoUpdate = false Log.w( LOG_TAG, "[RewardedAds][Privacy] consent info update failed code=${requestError.errorCode} message=${requestError.message.orEmpty()}", ) }, ) } private fun dispatchState(requestId: String) { dispatchResponse( JSONObject().apply { put("requestId", requestId) put("command", "getState") put("result", currentState()) }, ) } private fun showPrivacyOptions(requestId: String) { if (!canShowPrivacyOptions()) { Log.d(LOG_TAG, "[RewardedAds][Privacy] privacy options unavailable") dispatchResponse( JSONObject().apply { put("requestId", requestId) put("command", "showOptions") put("result", JSONObject().apply { put("shown", false) put("errorCode", "privacyOptionsUnavailable") put("message", "Privacy options unavailable") }) }, ) return } UserMessagingPlatform.showPrivacyOptionsForm(activity) { formError: FormError? -> if (formError != null) { Log.w( LOG_TAG, "[RewardedAds][Privacy] privacy options failed code=${formError.errorCode} message=${formError.message.orEmpty()}", ) dispatchError(requestId, "showOptionsFailed", formError.message ?: "Privacy options failed") return@showPrivacyOptionsForm } Log.d(LOG_TAG, "[RewardedAds][Privacy] privacy options shown") dispatchResponse( JSONObject().apply { put("requestId", requestId) put("command", "showOptions") put("result", JSONObject().apply { put("shown", true) }) }, ) } } private fun canShowPrivacyOptions(): Boolean { return didCompleteConsentInfoUpdate && consentInformation.privacyOptionsRequirementStatus == ConsentInformation.PrivacyOptionsRequirementStatus.REQUIRED } private fun currentState(): JSONObject { val canShowPrivacyOptions = canShowPrivacyOptions() val requiresConsentFlow = consentInformation.consentStatus == ConsentInformation.ConsentStatus.REQUIRED val status = if (didCompleteConsentInfoUpdate) { if (canShowPrivacyOptions) "available" else "unavailable" } else { "unavailable" } return JSONObject().apply { put("supported", true) put("canShowPrivacyOptions", canShowPrivacyOptions) put("requiresConsentFlow", requiresConsentFlow) put("status", status) } } private fun safePayload(arg: String?): JSONObject? { return try { if (arg.isNullOrBlank()) null else JSONObject(arg) } catch (_: Throwable) { null } } private fun dispatchError(requestId: String, code: String, message: String) { dispatchResponse( JSONObject().apply { put("requestId", requestId) put("command", "error") put("error", JSONObject().apply { put("code", code) put("message", message) }) }, ) } private fun dispatchResponse(payload: JSONObject) { val content = payload.toString() CocosHelper.runOnGameThread { JsbBridgeWrapper.getInstance().dispatchEventToScript(RESPONSE_EVENT, content) } } }