From e0587a1128e3a80de077b03829fe18a58782f4ef Mon Sep 17 00:00:00 2001 From: Dave Snabel-Caunt Date: Mon, 9 Sep 2024 15:45:36 +0100 Subject: [PATCH] EUID Support for GMA Plugin --- .../src/main/AndroidManifest.xml | 3 + .../java/com/uid2/dev/BannerActivity.java | 11 ++- .../java/com/uid2/dev/GMADevApplication.kt | 20 +++-- .../main/java/com/uid2/dev/utils/BundleEx.kt | 7 ++ .../main/java/com/uid2/dev/utils/ContextEx.kt | 10 +++ .../com/uid2/dev/utils/PackageManagerEx.kt | 14 ++++ .../securesignals/gma/EUIDMediationAdapter.kt | 76 +++++++++++++++++++ .../gma/EUIDMediationAdapterTest.kt | 29 +++++++ 8 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/BundleEx.kt create mode 100644 securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/ContextEx.kt create mode 100644 securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/PackageManagerEx.kt create mode 100644 securesignals-gma/src/main/java/com/uid2/securesignals/gma/EUIDMediationAdapter.kt create mode 100644 securesignals-gma/src/test/java/com/uid2/securesignals/gma/EUIDMediationAdapterTest.kt diff --git a/securesignals-gma-dev-app/src/main/AndroidManifest.xml b/securesignals-gma-dev-app/src/main/AndroidManifest.xml index 02047f6..1311467 100644 --- a/securesignals-gma-dev-app/src/main/AndroidManifest.xml +++ b/securesignals-gma-dev-app/src/main/AndroidManifest.xml @@ -16,6 +16,9 @@ android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-3940256099942544~3347511713"/> + + + diff --git a/securesignals-gma-dev-app/src/main/java/com/uid2/dev/BannerActivity.java b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/BannerActivity.java index 6a3d3e8..d5e4d37 100644 --- a/securesignals-gma-dev-app/src/main/java/com/uid2/dev/BannerActivity.java +++ b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/BannerActivity.java @@ -1,5 +1,8 @@ package com.uid2.dev; +import static com.uid2.dev.utils.BundleExKt.isEnvironmentEUID; +import static com.uid2.dev.utils.ContextExKt.getMetadata; + import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.util.Log; @@ -11,9 +14,9 @@ import com.google.android.gms.ads.RequestConfiguration; import com.google.android.gms.ads.initialization.InitializationStatus; import com.google.android.gms.ads.initialization.OnInitializationCompleteListener; +import com.uid2.EUIDManager; import com.uid2.UID2Manager; import com.uid2.data.UID2Identity; - import org.json.JSONObject; import java.io.BufferedReader; @@ -101,7 +104,11 @@ private void loadUID2Identity() { refreshFrom, refreshExpires, fromJsonIdentity.getRefreshResponseKey()); - UID2Manager.getInstance().setIdentity(identity); + if (isEnvironmentEUID(getMetadata(this))) { + EUIDManager.getInstance().setIdentity(identity); + } else { + UID2Manager.getInstance().setIdentity(identity); + } } catch (Exception e) { Log.e(TAG, "Error loading Identity: " + e); } diff --git a/securesignals-gma-dev-app/src/main/java/com/uid2/dev/GMADevApplication.kt b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/GMADevApplication.kt index 5becb71..0d34a6a 100644 --- a/securesignals-gma-dev-app/src/main/java/com/uid2/dev/GMADevApplication.kt +++ b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/GMADevApplication.kt @@ -2,8 +2,11 @@ package com.uid2.dev import android.app.Application import android.util.Log +import com.uid2.EUIDManager import com.uid2.UID2Manager import com.uid2.UID2Manager.Environment.Production +import com.uid2.dev.utils.getMetadata +import com.uid2.dev.utils.isEnvironmentEUID class GMADevApplication : Application() { @@ -13,11 +16,18 @@ class GMADevApplication : Application() { // Initialise the UID2Manager class. We will use it's DefaultNetworkSession rather than providing our own // custom implementation. This can be done to allow wrapping something like OkHttp. try { - UID2Manager.init( - context = this, - environment = Production, - isLoggingEnabled = true, - ) + if (getMetadata().isEnvironmentEUID()) { + EUIDManager.init( + context = this, + isLoggingEnabled = true, + ) + } else { + UID2Manager.init( + context = this, + environment = Production, + isLoggingEnabled = true, + ) + } } catch (ex: Exception) { Log.e("GMADevApplication", "Error initialising UID2Manager", ex) } diff --git a/securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/BundleEx.kt b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/BundleEx.kt new file mode 100644 index 0000000..2a68700 --- /dev/null +++ b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/BundleEx.kt @@ -0,0 +1,7 @@ +package com.uid2.dev.utils + +import android.os.Bundle + +private const val UID2_ENVIRONMENT_EUID = "uid2_environment_euid" + +fun Bundle.isEnvironmentEUID(): Boolean = getBoolean(UID2_ENVIRONMENT_EUID, false) diff --git a/securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/ContextEx.kt b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/ContextEx.kt new file mode 100644 index 0000000..91eef6c --- /dev/null +++ b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/ContextEx.kt @@ -0,0 +1,10 @@ +package com.uid2.dev.utils + +import android.content.Context +import android.content.pm.PackageManager +import android.os.Bundle + +fun Context.getMetadata(): Bundle = packageManager.getApplicationInfoCompat( + packageName, + PackageManager.GET_META_DATA, +).metaData diff --git a/securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/PackageManagerEx.kt b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/PackageManagerEx.kt new file mode 100644 index 0000000..e4f930c --- /dev/null +++ b/securesignals-gma-dev-app/src/main/java/com/uid2/dev/utils/PackageManagerEx.kt @@ -0,0 +1,14 @@ +package com.uid2.dev.utils + +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.os.Build + +fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int = 0): ApplicationInfo = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + @Suppress("WrongConstant") + getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(flags.toLong())) + } else { + @Suppress("DEPRECATION") + getApplicationInfo(packageName, flags) + } diff --git a/securesignals-gma/src/main/java/com/uid2/securesignals/gma/EUIDMediationAdapter.kt b/securesignals-gma/src/main/java/com/uid2/securesignals/gma/EUIDMediationAdapter.kt new file mode 100644 index 0000000..78e1e0f --- /dev/null +++ b/securesignals-gma/src/main/java/com/uid2/securesignals/gma/EUIDMediationAdapter.kt @@ -0,0 +1,76 @@ +package com.uid2.securesignals.gma + +import android.content.Context +import com.google.android.gms.ads.AdError +import com.google.android.gms.ads.mediation.InitializationCompleteCallback +import com.google.android.gms.ads.mediation.MediationConfiguration +import com.google.android.gms.ads.mediation.rtb.RtbAdapter +import com.google.android.gms.ads.mediation.rtb.RtbSignalData +import com.google.android.gms.ads.mediation.rtb.SignalCallbacks +import com.uid2.EUIDManager +import com.uid2.UID2 +import com.google.android.gms.ads.mediation.VersionInfo as GmaVersionInfo + +/** + * An implementation of Google's GMS RtbAdapter that integrates UID2 tokens, accessed via the UID2Manager. + */ +public class EUIDMediationAdapter : RtbAdapter() { + + /** + * Gets the version of the UID2 SDK. + */ + @Suppress("DEPRECATION") + public override fun getSDKVersionInfo(): GmaVersionInfo = UID2.getVersionInfo().let { + GmaVersionInfo(it.major, it.minor, it.patch) + } + + /** + * Gets the version of the UID2 Secure Signals plugin. + */ + @Suppress("DEPRECATION") + public override fun getVersionInfo(): GmaVersionInfo = PluginVersion.getVersionInfo().let { + GmaVersionInfo(it.major, it.minor, it.patch) + } + + /** + * Initialises the UID2 SDK with the given Context. + */ + override fun initialize( + context: Context, + initializationCompleteCallback: InitializationCompleteCallback, + mediationConfigurations: MutableList, + ) { + // It's possible that the UID2Manager is already initialised. If so, it's a no-op. + if (!EUIDManager.isInitialized()) { + EUIDManager.init(context) + } + + // After we've asked to initialize the manager, we should wait until it's complete before reporting success. + // This will potentially allow any previously persisted identity to be fully restored before we allow any + // signals to be collected. + EUIDManager.getInstance().addOnInitializedListener(initializationCompleteCallback::onInitializationSucceeded) + } + + /** + * Collects the UID2 advertising token, if available. + */ + override fun collectSignals(rtbSignalData: RtbSignalData, signalCallbacks: SignalCallbacks) { + EUIDManager.getInstance().let { manager -> + val token = manager.getAdvertisingToken() + if (token != null) { + signalCallbacks.onSuccess(token) + } else { + // We include the IdentityStatus in the "error" to have better visibility on why the Advertising Token + // was not present. There are a number of valid reasons why we don't have a token, but we are still + // required to report these as "failures". + signalCallbacks.onFailure( + AdError( + manager.currentIdentityStatus.value, + "No Advertising Token", + "UID2", + ), + ) + } + } + } +} diff --git a/securesignals-gma/src/test/java/com/uid2/securesignals/gma/EUIDMediationAdapterTest.kt b/securesignals-gma/src/test/java/com/uid2/securesignals/gma/EUIDMediationAdapterTest.kt new file mode 100644 index 0000000..edb1900 --- /dev/null +++ b/securesignals-gma/src/test/java/com/uid2/securesignals/gma/EUIDMediationAdapterTest.kt @@ -0,0 +1,29 @@ +package com.uid2.securesignals.gma + +import com.uid2.UID2 +import org.junit.Assert +import org.junit.Test + +class EUIDMediationAdapterTest { + @Test + fun `test SDK version`() { + val adapter = EUIDMediationAdapter() + val version = adapter.versionInfo + val expectedVersion = UID2.getVersionInfo() + + Assert.assertEquals(expectedVersion.major, version.majorVersion) + Assert.assertEquals(expectedVersion.minor, version.minorVersion) + Assert.assertEquals(expectedVersion.patch, version.microVersion) + } + + @Test + fun `test plugin version`() { + val adapter = EUIDMediationAdapter() + val version = adapter.sdkVersionInfo + val expectedVersion = PluginVersion.getVersionInfo() + + Assert.assertEquals(expectedVersion.major, version.majorVersion) + Assert.assertEquals(expectedVersion.minor, version.minorVersion) + Assert.assertEquals(expectedVersion.patch, version.microVersion) + } +}