Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EUID Support for IMA Plugin #101

Merged
merged 1 commit into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions securesignals-ima-dev-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
android:networkSecurityConfig="@xml/network_security_config"
tools:ignore="UnusedAttribute">

<!-- Metadata for toggling UID2 and EUID environments. If true, EUID is used. -->
<meta-data android:name="uid2_environment_euid" android:value="false"/>

<activity
android:name=".MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 IMADevApplication : Application() {

Expand All @@ -13,11 +16,18 @@ class IMADevApplication : 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 (baseContext.getMetadata().isEnvironmentEUID()) {
EUIDManager.init(
context = this,
isLoggingEnabled = true,
)
} else {
UID2Manager.init(
context = this,
environment = Production,
isLoggingEnabled = true,
)
}
} catch (ex: Exception) {
Log.e("IMADevApplication", "Error initialising UID2Manager", ex)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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.content.Context;
import android.media.AudioManager;
import android.os.Bundle;
Expand All @@ -22,6 +25,7 @@
import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
import com.uid2.EUIDManager;
import com.uid2.UID2Manager;
import com.uid2.data.UID2Identity;

Expand Down Expand Up @@ -227,7 +231,11 @@ private void loadUID2Identity() {
refreshExpires,
fromJsonIdentity.getRefreshResponseKey());

UID2Manager.getInstance().setIdentity(identity);
if (isEnvironmentEUID(getMetadata(getBaseContext()))) {
EUIDManager.getInstance().setIdentity(identity);
} else {
UID2Manager.getInstance().setIdentity(identity);
}
} catch (Exception e) {
Log.e(LOGTAG, "Error loading Identity: " + e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.uid2.securesignals.ima

import android.content.Context
import com.google.ads.interactivemedia.v3.api.VersionInfo
import com.google.ads.interactivemedia.v3.api.signals.SecureSignalsAdapter
import com.google.ads.interactivemedia.v3.api.signals.SecureSignalsCollectSignalsCallback
import com.google.ads.interactivemedia.v3.api.signals.SecureSignalsInitializeCallback
import com.uid2.EUIDManager
import com.uid2.UID2

/**
* A custom exception type that is used to report failures from the EUIDSecureSignalsAdapter when an error has occurred.
*/
public class EUIDSecureSignalsException(message: String? = null, cause: Throwable? = null) : Exception(message, cause)

/**
* An implementation of Google's IMA SecureSignalsAdapter that integrates UID2 tokens, accessed via the UID2Manager.
*/
public class EUIDSecureSignalsAdapter : SecureSignalsAdapter {

/**
* Gets the version of the UID2 SDK.
*/
public override fun getSDKVersion(): VersionInfo = UID2.getVersionInfo().let {
VersionInfo(it.major, it.minor, it.patch)
}

/**
* Gets the version of the UID2 Secure Signals plugin.
*/
public override fun getVersion(): VersionInfo = PluginVersion.getVersionInfo().let {
VersionInfo(it.major, it.minor, it.patch)
}

/**
* Initialises the UID2 SDK with the given Context.
*/
public override fun initialize(context: Context, callback: SecureSignalsInitializeCallback) {
// It's possible that the EUIDManager 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(callback::onSuccess)
}

/**
* Collects the UID2 advertising token, if available.
*/
public override fun collectSignals(context: Context, callback: SecureSignalsCollectSignalsCallback) {
EUIDManager.getInstance().let { manager ->
val token = manager.getAdvertisingToken()
if (token != null) {
callback.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".
callback.onFailure(
EUIDSecureSignalsException(
"No Advertising Token available (Status: ${manager.currentIdentityStatus.value})",
),
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.uid2.securesignals.ima

import com.uid2.UID2
import org.junit.Assert.assertEquals
import org.junit.Test

class EUIDSecureSignalsAdapterTest {
@Test
fun `test SDK version`() {
val adapter = UID2SecureSignalsAdapter()
val version = adapter.sdkVersion
val expectedVersion = UID2.getVersionInfo()

assertEquals(expectedVersion.major, version.majorVersion)
assertEquals(expectedVersion.minor, version.minorVersion)
assertEquals(expectedVersion.patch, version.microVersion)
}

@Test
fun `test plugin version`() {
val adapter = UID2SecureSignalsAdapter()
val version = adapter.version
val expectedVersion = PluginVersion.getVersionInfo()

assertEquals(expectedVersion.major, version.majorVersion)
assertEquals(expectedVersion.minor, version.minorVersion)
assertEquals(expectedVersion.patch, version.microVersion)
}
}
Loading