diff --git a/PrivacySandboxKotlin/build.gradle b/PrivacySandboxKotlin/build.gradle
index 0b6abd33..3ec06b8c 100644
--- a/PrivacySandboxKotlin/build.gradle
+++ b/PrivacySandboxKotlin/build.gradle
@@ -20,7 +20,7 @@ buildscript {
ext.privacy_sandbox_activity_version = "1.0.0-alpha01"
ext.privacy_sandbox_sdk_runtime_version = "1.0.0-alpha14"
ext.privacy_sandbox_tools_version = "1.0.0-alpha09"
- ext.privacy_sandbox_ui_version = "1.0.0-alpha09"
+ ext.privacy_sandbox_ui_version = "1.0.0-alpha12"
repositories {
mavenCentral()
}
diff --git a/PrivacySandboxKotlin/client-app/build.gradle b/PrivacySandboxKotlin/client-app/build.gradle
index edb852ad..3429394a 100644
--- a/PrivacySandboxKotlin/client-app/build.gradle
+++ b/PrivacySandboxKotlin/client-app/build.gradle
@@ -27,8 +27,7 @@ android {
defaultConfig {
applicationId "com.example.privacysandbox.client"
minSdkVersion 21
- compileSdk 34
- compileSdkExtension 12
+ compileSdk 35
targetSdkVersion 34
versionCode 2
versionName "1.01"
diff --git a/PrivacySandboxKotlin/client-app/src/main/java/com/example/client/MainActivity.kt b/PrivacySandboxKotlin/client-app/src/main/java/com/example/client/MainActivity.kt
index e1c8e7dc..3a83cbae 100644
--- a/PrivacySandboxKotlin/client-app/src/main/java/com/example/client/MainActivity.kt
+++ b/PrivacySandboxKotlin/client-app/src/main/java/com/example/client/MainActivity.kt
@@ -70,7 +70,8 @@ class MainActivity : AppCompatActivity() {
enum class MediationOption {
NONE,
RUNTIME_MEDIATEE,
- INAPP_MEDIATEE
+ INAPP_MEDIATEE,
+ REFRESH_MEDIATED_ADS
}
override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/PrivacySandboxKotlin/client-app/src/main/res/values/mediation_options.xml b/PrivacySandboxKotlin/client-app/src/main/res/values/mediation_options.xml
index d6a711ba..411f79a0 100644
--- a/PrivacySandboxKotlin/client-app/src/main/res/values/mediation_options.xml
+++ b/PrivacySandboxKotlin/client-app/src/main/res/values/mediation_options.xml
@@ -20,5 +20,6 @@
- No Mediation
- Runtime-Runtime Mediation
- Runtime-InApp Mediation
+ - Refresh Mediated Ad
diff --git a/PrivacySandboxKotlin/runtime-enabled-sdk-bundle/build.gradle b/PrivacySandboxKotlin/runtime-enabled-sdk-bundle/build.gradle
index 486c2e2d..792b1e58 100644
--- a/PrivacySandboxKotlin/runtime-enabled-sdk-bundle/build.gradle
+++ b/PrivacySandboxKotlin/runtime-enabled-sdk-bundle/build.gradle
@@ -19,8 +19,7 @@ plugins {
}
android {
- compileSdk 34
- compileSdkExtension 12
+ compileSdk 35
minSdk 21
bundle {
diff --git a/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/java/com/runtimeenabled/implementation/SdkSandboxedUiAdapterImpl.kt b/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/java/com/runtimeenabled/implementation/SdkSandboxedUiAdapterImpl.kt
index 3cb08bfc..be2e81a5 100644
--- a/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/java/com/runtimeenabled/implementation/SdkSandboxedUiAdapterImpl.kt
+++ b/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/java/com/runtimeenabled/implementation/SdkSandboxedUiAdapterImpl.kt
@@ -27,6 +27,7 @@ import androidx.privacysandbox.sdkruntime.core.activity.ActivityHolder
import androidx.privacysandbox.sdkruntime.core.activity.SdkSandboxActivityHandlerCompat
import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
import androidx.privacysandbox.ui.client.view.SandboxedSdkView
+import androidx.privacysandbox.ui.core.DelegatingSandboxedUiAdapter
import androidx.privacysandbox.ui.core.SandboxedUiAdapter
import androidx.privacysandbox.ui.provider.AbstractSandboxedUiAdapter
import com.runtimeenabled.R
diff --git a/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/java/com/runtimeenabled/implementation/SdkServiceImpl.kt b/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/java/com/runtimeenabled/implementation/SdkServiceImpl.kt
index 1657c8e9..76df6d01 100644
--- a/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/java/com/runtimeenabled/implementation/SdkServiceImpl.kt
+++ b/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/java/com/runtimeenabled/implementation/SdkServiceImpl.kt
@@ -17,10 +17,14 @@ package com.runtimeenabled.implementation
import android.content.Context
import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
import android.os.RemoteException
import android.util.Log
import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
import androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory
+import androidx.privacysandbox.ui.core.DelegatingSandboxedUiAdapter
+import androidx.privacysandbox.ui.core.ExperimentalFeatures
import com.runtimeenabled.R
import com.runtimeenabled.api.FullscreenAd
import com.runtimeenabled.api.SdkBannerRequest
@@ -36,6 +40,9 @@ import androidx.privacysandbox.ui.core.SessionObserverContext
import androidx.privacysandbox.ui.core.SessionObserverFactory
import androidx.privacysandbox.ui.provider.toCoreLibInfo
import com.runtimeenabled.api.MediateeAdapterInterface
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
class SdkServiceImpl(private val context: Context) : SdkService {
@@ -76,10 +83,34 @@ class SdkServiceImpl(private val context: Context) : SdkService {
// by the mediator to the app, without any wrapper, to avoid nested remote rendering. Since
// this will need to be returned in a Bundle (one SDK cannot use a shim object defined by
// another SDK), return type for getBanner will always be a Bundle.
+ @OptIn(ExperimentalFeatures.DelegatingAdapterApi::class)
override suspend fun getBanner(
request: SdkBannerRequest,
mediationType: String
): Bundle? {
+ if (mediationType == context.getString(R.string.mediation_option_refresh_mediated_ads)) {
+ val runtimeMediateeBanner = SandboxedUiAdapterFactory.createFromCoreLibInfo(checkNotNull(
+ mediateeAdapter?.getBannerAd(
+ request.appPackageName,
+ request.activityLauncher,
+ request.isWebViewBannerAd
+ )
+ ) { "No banner Ad received from mediatee!" })
+ // DelegatingSandboxedUiAdapter enables updating delegate from which different ads
+ // can be served without the client's involvement.
+ val delegatingAdapter = DelegatingSandboxedUiAdapter(
+ SdkSandboxedUiAdapterImpl(
+ context,
+ request,
+ runtimeMediateeBanner
+ ).toCoreLibInfo(context)
+ )
+ // Launches a function to refresh the ad after a few seconds
+ CoroutineScope(Dispatchers.IO).launch {
+ updateDelegateAfterSomeDelay(request, delegatingAdapter);
+ }
+ return delegatingAdapter.toCoreLibInfo(context)
+ }
if (mediationType == context.getString(R.string.mediation_option_none)) {
val bannerAdAdapter = SdkSandboxedUiAdapterImpl(context, request, null)
bannerAdAdapter.addObserverFactory(SessionObserverFactoryImpl())
@@ -108,6 +139,22 @@ class SdkServiceImpl(private val context: Context) : SdkService {
).toCoreLibInfo(context)
}
+ private suspend fun updateDelegateAfterSomeDelay(
+ request: SdkBannerRequest,
+ delegatingAdapter: DelegatingSandboxedUiAdapter
+ ) {
+ delay(10000)
+ val inAppMediateeBanner = inAppMediateeAdapter?.getBannerAd(
+ request.appPackageName,
+ request.activityLauncher,
+ request.isWebViewBannerAd
+ )
+ // Refresh the ad to show ads from another mediatee
+ if (inAppMediateeBanner != null) {
+ delegatingAdapter.updateDelegate(inAppMediateeBanner)
+ }
+ }
+
override suspend fun getFullscreenAd(mediationType: String): FullscreenAd {
if (mediationType == context.getString(R.string.mediation_option_none)) {
return FullscreenAdImpl(context, null, false)
diff --git a/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/res/values/mediation_options.xml b/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/res/values/mediation_options.xml
index 095a8449..cc79fa66 100644
--- a/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/res/values/mediation_options.xml
+++ b/PrivacySandboxKotlin/runtime-enabled-sdk/src/main/res/values/mediation_options.xml
@@ -18,5 +18,6 @@
NONE
RUNTIME_MEDIATEE
+ REFRESH_MEDIATED_ADS
INAPP_MEDIATEE