package com.topon import android.app.Activity import android.os.Build import com.facebook.react.bridge.Arguments import com.secmtp.sdk.core.api.ATAdConst import com.secmtp.sdk.core.api.ATAdInfo import com.secmtp.sdk.core.api.ATAdStatusInfo import com.secmtp.sdk.core.api.AdError import com.secmtp.sdk.rewardvideo.api.ATRewardVideoAd import com.secmtp.sdk.rewardvideo.api.ATRewardVideoListener import org.json.JSONException import org.json.JSONObject import java.lang.ref.WeakReference import java.util.HashMap class RewardedVideoHelper(module: ToponModule) : BaseHelper(module) { private var rewardVideoAd: ATRewardVideoAd? = null private var placementId: String = "" private var isReady: Boolean = false private var lastWindowState: WindowUiState? = null private var lastWindowActivity: WeakReference? = null private data class WindowUiState( val systemUiVisibility: Int, val statusBarColor: Int?, val navigationBarColor: Int?, val statusBarContrastEnforced: Boolean?, val navigationBarContrastEnforced: Boolean? ) private fun sanitizeScenario(input: String): String { val maxLen = 1024 return if (input.length > maxLen) { MsgTools.printMsg("showRewardedVideo scenario too long, truncating length ${input.length} to $maxLen") input.substring(0, maxLen) } else input } private fun ensureRewardVideoAd(initPlacementId: String) { if (rewardVideoAd == null || placementId != initPlacementId) { placementId = initPlacementId MsgTools.printMsg("initRewardedVideo placementId: $placementId") val context = currentActivity() ?: reactContext() rewardVideoAd = ATRewardVideoAd(context, placementId).apply { setAdListener(object : ATRewardVideoListener { override fun onRewardedVideoAdLoaded() { MsgTools.printMsg("onRewardedVideoAdLoaded: $placementId") val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) sendEvent(Const.RewardVideoCallback.LoadedCallbackKey, map) } override fun onRewardedVideoAdFailed(adError: AdError) { MsgTools.printMsg( "onRewardedVideoAdFailed: $placementId, ${adError.fullErrorInfo}" ) val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.ErrorMsg, adError.fullErrorInfo) sendEvent(Const.RewardVideoCallback.LoadFailCallbackKey, map) } override fun onRewardedVideoAdPlayStart(adInfo: ATAdInfo) { MsgTools.printMsg("onRewardedVideoAdPlayStart: $placementId") val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.AdInfo, adInfo.toString()) sendEvent(Const.RewardVideoCallback.PlayStartCallbackKey, map) } override fun onRewardedVideoAdPlayEnd(adInfo: ATAdInfo) { MsgTools.printMsg("onRewardedVideoAdPlayEnd: $placementId") val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.AdInfo, adInfo.toString()) sendEvent(Const.RewardVideoCallback.PlayEndCallbackKey, map) } override fun onRewardedVideoAdPlayFailed(adError: AdError, adInfo: ATAdInfo) { MsgTools.printMsg( "onRewardedVideoAdPlayFailed: $placementId, ${adError.fullErrorInfo}" ) runOnUiThread { restoreWindowUi() } val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.ErrorMsg, adError.fullErrorInfo) map.putString(Const.CallbackKey.AdInfo, adInfo.toString()) sendEvent(Const.RewardVideoCallback.PlayFailCallbackKey, map) } override fun onRewardedVideoAdClosed(adInfo: ATAdInfo) { MsgTools.printMsg("onRewardedVideoAdClosed: $placementId") runOnUiThread { restoreWindowUi() } val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.AdInfo, adInfo.toString()) sendEvent(Const.RewardVideoCallback.CloseCallbackKey, map) } override fun onRewardedVideoAdPlayClicked(adInfo: ATAdInfo) { MsgTools.printMsg("onRewardedVideoAdPlayClicked: $placementId") val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.AdInfo, adInfo.toString()) sendEvent(Const.RewardVideoCallback.ClickCallbackKey, map) } override fun onReward(adInfo: ATAdInfo) { MsgTools.printMsg("onReward: $placementId") val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.AdInfo, adInfo.toString()) sendEvent(Const.RewardVideoCallback.RewardCallbackKey, map) } }) } } } private fun captureWindowUi(activity: Activity) { val window = activity.window ?: return val decorView = window.decorView ?: return @Suppress("DEPRECATION") val systemUiVisibility = decorView.systemUiVisibility val state = WindowUiState( systemUiVisibility, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) window.statusBarColor else null, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) window.navigationBarColor else null, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) window.isStatusBarContrastEnforced else null, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) window.isNavigationBarContrastEnforced else null ) lastWindowState = state lastWindowActivity = WeakReference(activity) } private fun restoreWindowUi() { val state = lastWindowState ?: return val activity = lastWindowActivity?.get() ?: currentActivity() if (activity == null) { lastWindowState = null lastWindowActivity = null return } val window = activity.window ?: return val decorView = window.decorView ?: return @Suppress("DEPRECATION") run { decorView.systemUiVisibility = state.systemUiVisibility } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { state.statusBarColor?.let { window.statusBarColor = it } state.navigationBarColor?.let { window.navigationBarColor = it } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { state.statusBarContrastEnforced?.let { window.isStatusBarContrastEnforced = it } state.navigationBarContrastEnforced?.let { window.isNavigationBarContrastEnforced = it } } lastWindowState = null lastWindowActivity = null } fun loadRewardedVideo(placementId: String, settingsJson: String) { MsgTools.printMsg("loadRewardedVideo: $placementId, settings: $settingsJson") runOnUiThread { ensureRewardVideoAd(placementId) val ad = rewardVideoAd ?: return@runOnUiThread if (settingsJson.isNotEmpty()) { try { val jsonObject = JSONObject(settingsJson) val userId = jsonObject.optString(Const.USER_ID, "") val userData = jsonObject.optString(Const.USER_DATA, "") val localExtra = HashMap() localExtra[ATAdConst.KEY.USER_ID] = userId localExtra[ATAdConst.KEY.USER_CUSTOM_DATA] = userData fillMapFromJsonObject(localExtra, jsonObject) ad.setLocalExtra(localExtra) } catch (e: JSONException) { e.printStackTrace() } } ad.load() } } fun showVideo(scenario: String) { val safeScenario = sanitizeScenario(scenario) MsgTools.printMsg("showRewardedVideo: $placementId, scenario: $safeScenario") runOnUiThread { val ad = rewardVideoAd if (ad != null) { val activity = currentActivity() if (activity == null) { MsgTools.printMsg("showRewardedVideo error, current activity is null $placementId") val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.ErrorMsg, "current activity is null") sendEvent(Const.RewardVideoCallback.PlayFailCallbackKey, map) return@runOnUiThread } if (!ad.isAdReady) { MsgTools.printMsg("showRewardedVideo error, ad is not ready $placementId") val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.ErrorMsg, "ad is not ready") sendEvent(Const.RewardVideoCallback.PlayFailCallbackKey, map) return@runOnUiThread } captureWindowUi(activity) isReady = false if (safeScenario.isNotEmpty()) { ad.show(activity, safeScenario) } else { ad.show(activity) } } else { MsgTools.printMsg("showVideo error, you must call loadRewardVideo first $placementId") val map = Arguments.createMap() map.putString(Const.CallbackKey.PlacementId, placementId) map.putString(Const.CallbackKey.ErrorMsg, "you must call loadRewardVideo first") sendEvent(Const.RewardVideoCallback.LoadFailCallbackKey, map) } } } fun isAdReady(): Boolean { MsgTools.printMsg("rewarded isAdReady: $placementId") return try { rewardVideoAd?.isAdReady ?: run { MsgTools.printMsg("rewarded isAdReady error, you must call loadRewardedVideo first $placementId") isReady } } catch (t: Throwable) { MsgTools.printMsg("rewarded isAdReady Throwable: ${t.message}") isReady } } fun checkAdStatus(): String { MsgTools.printMsg("rewarded checkAdStatus: $placementId") return try { val statusInfo: ATAdStatusInfo? = rewardVideoAd?.checkAdStatus() if (statusInfo != null) { val jsonObject = JSONObject() jsonObject.put("isLoading", statusInfo.isLoading) jsonObject.put("isReady", statusInfo.isReady) jsonObject.put("adInfo", statusInfo.getATTopAdInfo()) val result = jsonObject.toString() MsgTools.printMsg("rewarded checkAdStatus: $placementId, $result") result } else { MsgTools.printMsg("rewarded checkAdStatus error, you must call loadRewardedVideo first $placementId") "" } } catch (t: Throwable) { MsgTools.printMsg("rewarded checkAdStatus Throwable: ${t.message}") "" } } }