From 5ca2b2be7c6d0bbd11f4f01171394f378c151ae1 Mon Sep 17 00:00:00 2001 From: zhangketong Date: Tue, 22 Jul 2025 14:37:03 +0800 Subject: [PATCH] Update Pangle Adapter.Do not serve ads to children --- .../adapters/pangle/PangleAdapter.kt | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/Adapters/Pangle/pangleadapter/src/main/java/com/ironsource/adapters/pangle/PangleAdapter.kt b/Adapters/Pangle/pangleadapter/src/main/java/com/ironsource/adapters/pangle/PangleAdapter.kt index e96cca3..051537d 100644 --- a/Adapters/Pangle/pangleadapter/src/main/java/com/ironsource/adapters/pangle/PangleAdapter.kt +++ b/Adapters/Pangle/pangleadapter/src/main/java/com/ironsource/adapters/pangle/PangleAdapter.kt @@ -84,6 +84,22 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), // Pangle errors const val PANGLE_NO_FILL_ERROR_CODE = 20001 + // Pangle not allow child error code + const val PANGLE_NOT_ALLOW_CHILD_ERROR_CODE = 20002 + // Pangle not allow child error code + const val PANGLE_NOT_ALLOW_CHILD_ERROR_MSG = "Pangle_COPPA indicates the user is a child. Pangle SDK V71 or higher does not support child users." + + private const val PANGLE_CHILD_DIRECTED_TYPE_CHILD = 1 + private const val PANGLE_CHILD_DIRECTED_TYPE_NON_CHILD = 0 + private const val PANGLE_CHILD_DIRECTED_TYPE_DEFAULT = -1 + + //Pangle defaultChildDirected + private var mChildDirected = PANGLE_CHILD_DIRECTED_TYPE_DEFAULT + + + // Meta data flags + private const val META_DATA_PANGLE_COPPA_KEY = "Pangle_COPPA" + // Pangle Builder private val mPAGConfigBuilder = PAGConfig.Builder() @@ -146,6 +162,11 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), mInitState = InitState.INIT_STATE_IN_PROGRESS IronLog.ADAPTER_API.verbose("appId = $appId") + if (isChild()){ + initializationFailure(PANGLE_NOT_ALLOW_CHILD_ERROR_CODE, PANGLE_NOT_ALLOW_CHILD_ERROR_MSG) + return + } + val context = ContextProvider.getInstance().applicationContext val initConfig = mPAGConfigBuilder .appId(appId) @@ -171,6 +192,13 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), } } + /** + * Whether to allow the use of pangle. If it is a child , it is not allowed + */ + private fun isChild(): Boolean { + return mChildDirected == PANGLE_CHILD_DIRECTED_TYPE_CHILD + } + private fun initializationSuccess() { IronLog.ADAPTER_CALLBACK.verbose() @@ -255,6 +283,12 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), val slotId = config?.optString(SLOT_ID_KEY) val appId = config?.optString(APP_ID_KEY) + if (isChild()){ + listener.onRewardedVideoInitFailed(ErrorBuilder.buildInitFailedError( + PANGLE_NOT_ALLOW_CHILD_ERROR_MSG, IronSourceConstants.REWARDED_VIDEO_AD_UNIT)) + return + } + if (slotId.isNullOrEmpty()) { IronLog.INTERNAL.error("Missing param - $SLOT_ID_KEY") listener.onRewardedVideoInitFailed(ErrorBuilder.buildInitFailedError("Missing params - $SLOT_ID_KEY", IronSourceConstants.REWARDED_VIDEO_AD_UNIT)) @@ -294,6 +328,13 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), val slotId = config?.optString(SLOT_ID_KEY) val appId = config?.optString(APP_ID_KEY) + if (isChild()){ + IronLog.INTERNAL.error(PANGLE_NOT_ALLOW_CHILD_ERROR_MSG) + listener.onRewardedVideoAvailabilityChanged(false) + return + } + + if (slotId.isNullOrEmpty()) { IronLog.INTERNAL.error("Missing param - $SLOT_ID_KEY") listener.onRewardedVideoAvailabilityChanged(false) @@ -346,6 +387,15 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), val rewardedVideoAdListener = PangleRewardedVideoAdListener(listener, WeakReference(this), slotId) mSlotIdToRewardedVideoAdListener[slotId] = rewardedVideoAdListener + + if (isChild()) { + rewardedVideoAdListener.onError( + PANGLE_NOT_ALLOW_CHILD_ERROR_CODE, + PANGLE_NOT_ALLOW_CHILD_ERROR_MSG + ) + return + } + val request = PAGRewardedRequest() if (serverData != null) { @@ -361,6 +411,15 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), val slotId = config.optString(SLOT_ID_KEY) IronLog.ADAPTER_API.verbose("slotId = $slotId") + if (isChild()) { + listener.onRewardedVideoAdShowFailed( + ErrorBuilder.buildShowFailedError( + IronSourceConstants.REWARDED_VIDEO_AD_UNIT, PANGLE_NOT_ALLOW_CHILD_ERROR_MSG + ) + ) + return + } + if (isRewardedVideoAvailable(config)) { val activity = ContextProvider.getInstance().currentActiveActivity @@ -414,6 +473,12 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), val slotId = config?.optString(SLOT_ID_KEY) val appId = config?.optString(APP_ID_KEY) + if (isChild()){ + listener.onInterstitialInitFailed(ErrorBuilder.buildInitFailedError( + PANGLE_NOT_ALLOW_CHILD_ERROR_MSG, IronSourceConstants.INTERSTITIAL_AD_UNIT)) + return + } + if (slotId.isNullOrEmpty()) { IronLog.INTERNAL.error("Missing param - $SLOT_ID_KEY") listener.onInterstitialInitFailed(ErrorBuilder.buildInitFailedError("Missing params - $SLOT_ID_KEY", IronSourceConstants.INTERSTITIAL_AD_UNIT)) @@ -467,6 +532,13 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), val interstitialAdListener = PangleInterstitialAdListener(listener, WeakReference(this), slotId) mSlotIdToInterstitialAdListener[slotId] = interstitialAdListener + + if (isChild()) { + interstitialAdListener.onError(PANGLE_NOT_ALLOW_CHILD_ERROR_CODE, + PANGLE_NOT_ALLOW_CHILD_ERROR_MSG) + return + } + val request = PAGInterstitialRequest() if (serverData != null) { @@ -482,6 +554,15 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), val slotId = config.optString(SLOT_ID_KEY) IronLog.ADAPTER_API.verbose("slotId = $slotId") + if (isChild()) { + listener.onInterstitialAdShowFailed( + ErrorBuilder.buildShowFailedError( + IronSourceConstants.INTERSTITIAL_AD_UNIT, PANGLE_NOT_ALLOW_CHILD_ERROR_MSG + ) + ) + return + } + if (isInterstitialReady(config)) { val activity = ContextProvider.getInstance().currentActiveActivity mSlotIdToInterstitialAd[slotId]?.let { interstitialAd -> @@ -529,6 +610,12 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), val slotId = config?.optString(SLOT_ID_KEY) val appId = config?.optString(APP_ID_KEY) + if (isChild()) { + listener.onBannerInitFailed(ErrorBuilder.buildInitFailedError( + PANGLE_NOT_ALLOW_CHILD_ERROR_MSG, IronSourceConstants.BANNER_AD_UNIT)) + return + } + if (slotId.isNullOrEmpty()) { IronLog.INTERNAL.error("Missing param - $SLOT_ID_KEY") listener.onBannerInitFailed(ErrorBuilder.buildInitFailedError("Missing params - $SLOT_ID_KEY", IronSourceConstants.BANNER_AD_UNIT)) @@ -580,6 +667,14 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), val bannerAdListener = PangleBannerAdListener(listener, WeakReference(this), slotId, layoutParams) mSlotIdToBannerAdListener[slotId] = bannerAdListener + if (isChild()) { + bannerAdListener.onError( + PANGLE_NOT_ALLOW_CHILD_ERROR_CODE, + PANGLE_NOT_ALLOW_CHILD_ERROR_MSG + ) + return + } + val adSize = getBannerSize(banner.size) val bannerRequest = PAGBannerRequest(adSize) bannerRequest.adString = serverData @@ -678,9 +773,33 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), MetaDataUtils.isValidCCPAMetaData(key, value) -> { setCCPAValue(MetaDataUtils.getMetaDataBooleanValue(value)) } + MetaDataUtils.isValidMetaData(key, META_DATA_PANGLE_COPPA_KEY, value) -> { + setCOPPAValue(value) + } } } + private fun setCOPPAValue(value: String) { + val coppaValueString : String + when (value.toIntOrNull()) { + PANGLE_CHILD_DIRECTED_TYPE_CHILD -> { + mChildDirected = PANGLE_CHILD_DIRECTED_TYPE_CHILD + coppaValueString = "PAG_CHILD_DIRECTED_TYPE_CHILD" + } + + PANGLE_CHILD_DIRECTED_TYPE_NON_CHILD -> { + mChildDirected = PANGLE_CHILD_DIRECTED_TYPE_NON_CHILD + coppaValueString = "PAG_CHILD_DIRECTED_TYPE_NON_CHILD" + } + + else -> { + mChildDirected = PANGLE_CHILD_DIRECTED_TYPE_DEFAULT + coppaValueString = "PAG_CHILD_DIRECTED_TYPE_DEFAULT" + } + } + IronLog.ADAPTER_API.verbose("coppaValue = $coppaValueString") + } + private fun setCCPAValue(doNotSell: Boolean) { val ccpaValue: Int @@ -823,6 +942,10 @@ class PangleAdapter(providerName: String) : AbstractAdapter(providerName), biddingDataCallback.onFailure("$error - Pangle") return } + if (isChild()) { + biddingDataCallback.onFailure("$PANGLE_NOT_ALLOW_CHILD_ERROR_MSG - Pangle") + return + } val pagBiddingRequest = PAGBiddingRequest().apply { slotId = slotid