package com.bigcrunch.ads.internal import android.content.Context import android.preference.PreferenceManager /** * Centralized privacy signal store * * Manages GDPR, CCPA, and COPPA privacy signals for the SDK. * Reads IAB TCF/USP standard keys from SharedPreferences when available, * and provides structured objects for bid request construction. */ internal class PrivacyStore(private val context: Context) { private val lock = Any() // SDK-set values (from public API) @Volatile private var _gdprConsentString: String? = null @Volatile private var _gdprApplies: Boolean? = null @Volatile private var _ccpaString: String? = null @Volatile private var _coppaApplies: Boolean = false companion object { // IAB standard SharedPreferences keys private const val IAB_TCF_CONSENT_KEY = "IABTCF_TCString" private const val IAB_TCF_GDPR_APPLIES_KEY = "IABTCF_gdprApplies" private const val IAB_USP_STRING_KEY = "IABUSPrivacy_String" } // MARK: - Setters (called from public API) fun setGdprConsent(consent: String) { synchronized(lock) { _gdprApplies = true _gdprConsentString = consent } BCLogger.d("PrivacyStore", "GDPR consent set") } fun setCcpaString(ccpa: String) { synchronized(lock) { _ccpaString = ccpa } // Also write to IAB standard key for CMP interop PreferenceManager.getDefaultSharedPreferences(context) .edit() .putString(IAB_USP_STRING_KEY, ccpa) .apply() BCLogger.d("PrivacyStore", "CCPA string set") } fun setCoppaApplies(applies: Boolean) { synchronized(lock) { _coppaApplies = applies } BCLogger.d("PrivacyStore", "COPPA set to $applies") } // MARK: - Getters /** Effective GDPR consent string (SDK-set takes priority, then IAB TCF) */ val gdprConsentString: String? get() = synchronized(lock) { _gdprConsentString } ?: iabPrefs.getString(IAB_TCF_CONSENT_KEY, null) /** Whether GDPR applies (SDK-set takes priority, then IAB TCF) */ val gdprApplies: Boolean? get() { synchronized(lock) { _gdprApplies?.let { return it } } val prefs = iabPrefs return if (prefs.contains(IAB_TCF_GDPR_APPLIES_KEY)) { prefs.getInt(IAB_TCF_GDPR_APPLIES_KEY, 0) == 1 } else { null } } /** Effective CCPA/USP string (SDK-set takes priority, then IAB USP) */ val ccpaString: String? get() = synchronized(lock) { _ccpaString } ?: iabPrefs.getString(IAB_USP_STRING_KEY, null) val coppaApplies: Boolean get() = synchronized(lock) { _coppaApplies } private val iabPrefs get() = PreferenceManager.getDefaultSharedPreferences(context) // MARK: - Bid Request Helpers /** Build the `regs` object for an OpenRTB bid request */ fun buildRegsMap(): Map { val regs = mutableMapOf() val ext = mutableMapOf() regs["coppa"] = if (coppaApplies) 1 else 0 gdprApplies?.let { ext["gdpr"] = if (it) 1 else 0 } ccpaString?.let { ext["us_privacy"] = it } if (ext.isNotEmpty()) { regs["ext"] = ext } return regs } /** Build the `user` object for an OpenRTB bid request */ fun buildUserMap(): Map { val user = mutableMapOf() val ext = mutableMapOf() gdprConsentString?.let { ext["consent"] = it } if (ext.isNotEmpty()) { user["ext"] = ext } return user } }