Merge back compat support to androidx-main
This copies over the changes from both ag/22316069 and ag/24692966 because the cherrypick tool failed. In addition to the testing below, I verified that all the modified files are identical between androidx-platform-dev and androidx-main after this change.
Bug: 299949487
Test: Run all unit tests with the following configurations:
* U - all tests run and pass except "OlderVersions" tests, which are skipped
* T release - skips all tests that check for ext4 or ext5, others pass
* T with ext4 - will run as presubmit
* T with ext5 - will run as presubmit
* S release - skips all tests that have version checks, others pass
* S with M-2023-10 installed via train installer - all tests run and pass except for "OlderVersions" tests and Fledge e2e
* Same as above, but with updated webview - all tests run and pass except for "OlderVersions" tests
Note that when installing the M-2023-10 train, you need to install all of primary, telemetry, and timezone, or the sdkext version will not bump to 9.
Change-Id: Ia3e9c292d6711b32839da3920d8e60e53ae60398
diff --git a/privacysandbox/ads/ads-adservices-java/build.gradle b/privacysandbox/ads/ads-adservices-java/build.gradle
index d65ff5c0..b3a4b71 100644
--- a/privacysandbox/ads/ads-adservices-java/build.gradle
+++ b/privacysandbox/ads/ads-adservices-java/build.gradle
@@ -36,8 +36,10 @@
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.0'
androidTestImplementation project(path: ':privacysandbox:ads:ads-adservices')
+ androidTestImplementation project(path: ':javascriptengine:javascriptengine')
androidTestImplementation(libs.junit)
androidTestImplementation(libs.kotlinTestJunit)
+ androidTestImplementation(libs.multidex)
androidTestImplementation(libs.testCore)
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testRunner)
@@ -46,9 +48,14 @@
androidTestImplementation(libs.mockitoCore4, excludes.bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation(libs.dexmakerMockitoInline, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockitoInlineExtended)
}
android {
+ defaultConfig {
+ multiDexEnabled = true
+ }
+
namespace "androidx.privacysandbox.ads.adservices.java"
}
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/AndroidManifest.xml b/privacysandbox/ads/ads-adservices-java/src/androidTest/AndroidManifest.xml
index 90665d4..aa19a69 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/AndroidManifest.xml
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/AndroidManifest.xml
@@ -14,11 +14,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS" />
<uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
<uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
<uses-permission android:name="android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCE" />
+ <uses-sdk tools:overrideLibrary="androidx.javascriptengine" />
<application>
<property android:name="android.adservices.AD_SERVICES_CONFIG"
android:resource="@xml/ad_services_config" />
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/VersionCompatUtil.kt b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/VersionCompatUtil.kt
new file mode 100644
index 0000000..d4ad1a2
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/VersionCompatUtil.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.java
+
+import android.os.Build
+import android.os.ext.SdkExtensions
+import androidx.test.filters.SdkSuppress
+
+@SdkSuppress(minSdkVersion = 30)
+object VersionCompatUtil {
+ fun isTPlusWithMinAdServicesVersion(minVersion: Int): Boolean {
+ return Build.VERSION.SDK_INT >= 33 &&
+ SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES) >= minVersion
+ }
+
+ fun isSWithMinExtServicesVersion(minVersion: Int): Boolean {
+ return (Build.VERSION.SDK_INT == 31 || Build.VERSION.SDK_INT == 32) &&
+ SdkExtensions.getExtensionVersion(Build.VERSION_CODES.S) >= minVersion
+ }
+
+ fun isTestableVersion(minAdServicesVersion: Int, minExtServicesVersion: Int): Boolean {
+ return isTPlusWithMinAdServicesVersion(minAdServicesVersion) ||
+ isSWithMinExtServicesVersion(minExtServicesVersion)
+ }
+}
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/adid/AdIdManagerFuturesTest.kt b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/adid/AdIdManagerFuturesTest.kt
index 5f20ba7..35d5109 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/adid/AdIdManagerFuturesTest.kt
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/adid/AdIdManagerFuturesTest.kt
@@ -19,16 +19,18 @@
import android.content.Context
import android.os.Looper
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
-import androidx.annotation.RequiresExtension
import androidx.privacysandbox.ads.adservices.adid.AdId
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth
import com.google.common.util.concurrent.ListenableFuture
import kotlin.test.assertNotEquals
+import org.junit.After
import org.junit.Assert
import org.junit.Assume
import org.junit.Before
@@ -36,6 +38,8 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mockito
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
@SmallTest
@@ -44,25 +48,45 @@
@SdkSuppress(minSdkVersion = 30)
class AdIdManagerFuturesTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdExtServicesSdkExtVersion = VersionCompatUtil.isSWithMinExtServicesVersion(9)
+
@Before
fun setUp() {
- mContext = Mockito.spy(ApplicationProvider.getApplicationContext<Context>())
+ mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.adid.AdIdManager::class.java)
+ .startMocking()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testAdIdOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
- Assume.assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeFalse("maxSdkVersion = API 33 ext 3 or API 31/32 ext 8",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9))
Truth.assertThat(AdIdManagerFutures.from(mContext)).isEqualTo(null)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testAdIdAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val adIdManager = mockAdIdManager(mContext)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 4,
+ /* minExtServicesVersion=*/ 9))
+
+ val adIdManager = mockAdIdManager(mContext, mValidAdExtServicesSdkExtVersion)
setupResponse(adIdManager)
val managerCompat = AdIdManagerFutures.from(mContext)
@@ -76,16 +100,23 @@
Mockito.verify(adIdManager).getAdId(ArgumentMatchers.any(), ArgumentMatchers.any())
}
- @SuppressWarnings("NewApi")
@SdkSuppress(minSdkVersion = 30)
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
companion object {
private lateinit var mContext: Context
- private fun mockAdIdManager(spyContext: Context): android.adservices.adid.AdIdManager {
+ private fun mockAdIdManager(
+ spyContext: Context,
+ isExtServices: Boolean
+ ): android.adservices.adid.AdIdManager {
val adIdManager = Mockito.mock(android.adservices.adid.AdIdManager::class.java)
- Mockito.`when`(spyContext.getSystemService(
- android.adservices.adid.AdIdManager::class.java)).thenReturn(adIdManager)
+ // mock the .get() method if using extServices version, otherwise mock getSystemService
+ if (isExtServices) {
+ `when`(android.adservices.adid.AdIdManager.get(ArgumentMatchers.any()))
+ .thenReturn(adIdManager)
+ } else {
+ `when`(spyContext.getSystemService(
+ android.adservices.adid.AdIdManager::class.java)).thenReturn(adIdManager)
+ }
return adIdManager
}
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/adselection/AdSelectionManagerFuturesTest.kt b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/adselection/AdSelectionManagerFuturesTest.kt
index af4ef91..afc5c68 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/adselection/AdSelectionManagerFuturesTest.kt
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/adselection/AdSelectionManagerFuturesTest.kt
@@ -19,20 +19,22 @@
import android.content.Context
import android.net.Uri
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
-import androidx.annotation.RequiresExtension
import androidx.privacysandbox.ads.adservices.adselection.AdSelectionConfig
import androidx.privacysandbox.ads.adservices.adselection.AdSelectionOutcome
import androidx.privacysandbox.ads.adservices.adselection.ReportImpressionRequest
import androidx.privacysandbox.ads.adservices.common.AdSelectionSignals
import androidx.privacysandbox.ads.adservices.common.AdTechIdentifier
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil
import androidx.privacysandbox.ads.adservices.java.adselection.AdSelectionManagerFutures.Companion.from
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth
import com.google.common.util.concurrent.ListenableFuture
+import org.junit.After
import org.junit.Assert
import org.junit.Assume
import org.junit.Before
@@ -46,6 +48,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
@SmallTest
@SuppressWarnings("NewApi")
@@ -53,27 +56,46 @@
@SdkSuppress(minSdkVersion = 30)
class AdSelectionManagerFuturesTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdExtServicesSdkExtVersion = VersionCompatUtil.isSWithMinExtServicesVersion(9)
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.adselection.AdSelectionManager::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testAdSelectionOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeFalse("maxSdkVersion = API 33 ext 3 or API 31/32 ext 8",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9))
Truth.assertThat(from(mContext)).isEqualTo(null)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testSelectAds() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 4,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val adSelectionManager = mockAdSelectionManager(mContext)
+ val adSelectionManager = mockAdSelectionManager(mContext, mValidAdExtServicesSdkExtVersion)
setupAdSelectionResponse(adSelectionManager)
val managerCompat = from(mContext)
@@ -95,12 +117,13 @@
@Test
@SuppressWarnings("NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testReportImpression() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 4,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val adSelectionManager = mockAdSelectionManager(mContext)
+ val adSelectionManager = mockAdSelectionManager(mContext, mValidAdExtServicesSdkExtVersion)
setupAdSelectionResponse(adSelectionManager)
val managerCompat = from(mContext)
val reportImpressionRequest = ReportImpressionRequest(adSelectionId, adSelectionConfig)
@@ -119,7 +142,6 @@
@SuppressWarnings("NewApi")
@SdkSuppress(minSdkVersion = 30)
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
companion object {
private lateinit var mContext: Context
private const val adSelectionId = 1234L
@@ -148,13 +170,20 @@
private val renderUri = Uri.parse("render-uri.com")
private fun mockAdSelectionManager(
- spyContext: Context
+ spyContext: Context,
+ isExtServices: Boolean
): android.adservices.adselection.AdSelectionManager {
val adSelectionManager =
mock(android.adservices.adselection.AdSelectionManager::class.java)
- `when`(spyContext.getSystemService(
- android.adservices.adselection.AdSelectionManager::class.java))
- .thenReturn(adSelectionManager)
+ // mock the .get() method if using extServices version, otherwise mock getSystemService
+ if (isExtServices) {
+ `when`(android.adservices.adselection.AdSelectionManager.get(any()))
+ .thenReturn(adSelectionManager)
+ } else {
+ `when`(spyContext.getSystemService(
+ android.adservices.adselection.AdSelectionManager::class.java))
+ .thenReturn(adSelectionManager)
+ }
return adSelectionManager
}
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/appsetid/AppSetIdManagerFuturesTest.kt b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/appsetid/AppSetIdManagerFuturesTest.kt
index a540f73..b92fa9a 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/appsetid/AppSetIdManagerFuturesTest.kt
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/appsetid/AppSetIdManagerFuturesTest.kt
@@ -19,21 +19,24 @@
import android.content.Context
import android.os.Looper
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
-import androidx.annotation.RequiresExtension
import androidx.privacysandbox.ads.adservices.appsetid.AppSetId
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.ListenableFuture
import kotlin.test.assertNotEquals
+import org.junit.After
import org.junit.Assert
import org.junit.Assume
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.mock
@@ -43,32 +46,50 @@
import org.mockito.invocation.InvocationOnMock
@SmallTest
+@SuppressWarnings("NewApi")
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = 30)
class AppSetIdManagerFuturesTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdExtServicesSdkExtVersion = VersionCompatUtil.isSWithMinExtServicesVersion(9)
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.appsetid.AppSetIdManager::class.java)
+ .startMocking()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testAppSetIdOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeFalse("maxSdkVersion = API 33 ext 3 or API 31/32 ext 8",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9))
assertThat(AppSetIdManagerFutures.from(mContext)).isEqualTo(null)
}
@Test
- @SuppressWarnings("NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testAppSetIdAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 4,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val appSetIdManager = mockAppSetIdManager(mContext)
+ val appSetIdManager = mockAppSetIdManager(mContext, mValidAdExtServicesSdkExtVersion)
setupResponse(appSetIdManager)
val managerCompat = AppSetIdManagerFutures.from(mContext)
@@ -82,19 +103,24 @@
verify(appSetIdManager).getAppSetId(any(), any())
}
- @SuppressWarnings("NewApi")
@SdkSuppress(minSdkVersion = 30)
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
companion object {
private lateinit var mContext: Context
private fun mockAppSetIdManager(
- spyContext: Context
+ spyContext: Context,
+ isExtServices: Boolean
): android.adservices.appsetid.AppSetIdManager {
val appSetIdManager = mock(android.adservices.appsetid.AppSetIdManager::class.java)
- `when`(spyContext.getSystemService(
- android.adservices.appsetid.AppSetIdManager::class.java))
- .thenReturn(appSetIdManager)
+ // mock the .get() method if using extServices version, otherwise mock getSystemService
+ if (isExtServices) {
+ `when`(android.adservices.appsetid.AppSetIdManager.get(ArgumentMatchers.any()))
+ .thenReturn(appSetIdManager)
+ } else {
+ `when`(spyContext.getSystemService(
+ android.adservices.appsetid.AppSetIdManager::class.java))
+ .thenReturn(appSetIdManager)
+ }
return appSetIdManager
}
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/customaudience/CustomAudienceManagerFuturesTest.kt b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/customaudience/CustomAudienceManagerFuturesTest.kt
index 31b287d..9da1419 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/customaudience/CustomAudienceManagerFuturesTest.kt
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/customaudience/CustomAudienceManagerFuturesTest.kt
@@ -20,8 +20,6 @@
import android.content.Context
import android.net.Uri
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
-import androidx.annotation.RequiresExtension
import androidx.privacysandbox.ads.adservices.common.AdData
import androidx.privacysandbox.ads.adservices.common.AdSelectionSignals
import androidx.privacysandbox.ads.adservices.common.AdTechIdentifier
@@ -29,13 +27,17 @@
import androidx.privacysandbox.ads.adservices.customaudience.JoinCustomAudienceRequest
import androidx.privacysandbox.ads.adservices.customaudience.LeaveCustomAudienceRequest
import androidx.privacysandbox.ads.adservices.customaudience.TrustedBiddingData
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil
import androidx.privacysandbox.ads.adservices.java.customaudience.CustomAudienceManagerFutures.Companion.from
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth
import java.time.Instant
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.Test
@@ -48,6 +50,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
@SmallTest
@SuppressWarnings("NewApi")
@@ -55,27 +58,47 @@
@SdkSuppress(minSdkVersion = 30)
class CustomAudienceManagerFuturesTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdExtServicesSdkExtVersion = VersionCompatUtil.isSWithMinExtServicesVersion(9)
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.customaudience.CustomAudienceManager::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeFalse("maxSdkVersion = API 33 ext 3 or API 31/32 ext 8",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9))
Truth.assertThat(from(mContext)).isEqualTo(null)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testJoinCustomAudience() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 4,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val customAudienceManager = mockCustomAudienceManager(mContext)
+ val customAudienceManager =
+ mockCustomAudienceManager(mContext, mValidAdExtServicesSdkExtVersion)
setupResponse(customAudienceManager)
val managerCompat = from(mContext)
@@ -100,12 +123,14 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testLeaveCustomAudience() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 4,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val customAudienceManager = mockCustomAudienceManager(mContext)
+ val customAudienceManager =
+ mockCustomAudienceManager(mContext, mValidAdExtServicesSdkExtVersion)
setupResponse(customAudienceManager)
val managerCompat = from(mContext)
@@ -124,7 +149,6 @@
}
@SdkSuppress(minSdkVersion = 30)
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
companion object {
private lateinit var mContext: Context
private val uri: Uri = Uri.parse("abc.com")
@@ -138,10 +162,18 @@
private const val metadata = "metadata"
private val ads: List<AdData> = listOf(AdData(uri, metadata))
- private fun mockCustomAudienceManager(spyContext: Context): CustomAudienceManager {
+ private fun mockCustomAudienceManager(
+ spyContext: Context,
+ isExtServices: Boolean
+ ): CustomAudienceManager {
val customAudienceManager = mock(CustomAudienceManager::class.java)
- `when`(spyContext.getSystemService(CustomAudienceManager::class.java))
- .thenReturn(customAudienceManager)
+ // mock the .get() method if using extServices version, otherwise mock getSystemService
+ if (isExtServices) {
+ `when`(CustomAudienceManager.get(any())).thenReturn(customAudienceManager)
+ } else {
+ `when`(spyContext.getSystemService(CustomAudienceManager::class.java))
+ .thenReturn(customAudienceManager)
+ }
return customAudienceManager
}
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/FledgeCtsDebuggableTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/FledgeCtsDebuggableTest.java
index 7925188..fdd7e82 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/FledgeCtsDebuggableTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/FledgeCtsDebuggableTest.java
@@ -26,6 +26,7 @@
import android.util.Log;
import androidx.annotation.RequiresApi;
+import androidx.javascriptengine.JavaScriptSandbox;
import androidx.privacysandbox.ads.adservices.adselection.AdSelectionConfig;
import androidx.privacysandbox.ads.adservices.adselection.AdSelectionManager;
import androidx.privacysandbox.ads.adservices.adselection.AdSelectionOutcome;
@@ -36,7 +37,7 @@
import androidx.privacysandbox.ads.adservices.customaudience.CustomAudience;
import androidx.privacysandbox.ads.adservices.customaudience.JoinCustomAudienceRequest;
import androidx.privacysandbox.ads.adservices.customaudience.TrustedBiddingData;
-import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo;
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil;
import androidx.privacysandbox.ads.adservices.java.adselection.AdSelectionManagerFutures;
import androidx.privacysandbox.ads.adservices.java.customaudience.CustomAudienceManagerFutures;
import androidx.test.core.app.ApplicationProvider;
@@ -175,6 +176,10 @@
testUtil.disableFledgeEnrollmentCheck(true);
testUtil.enableAdServiceSystemService(true);
testUtil.enforceFledgeJsIsolateMaxHeapSize(false);
+
+ if (VersionCompatUtil.INSTANCE.isSWithMinExtServicesVersion(9)) {
+ testUtil.enableBackCompat();
+ }
}
@AfterClass
@@ -196,10 +201,15 @@
testUtil.disableFledgeEnrollmentCheck(false);
testUtil.enableAdServiceSystemService(false);
testUtil.enforceFledgeJsIsolateMaxHeapSize(true);
+
+ if (VersionCompatUtil.INSTANCE.isSWithMinExtServicesVersion(9)) {
+ testUtil.disableBackCompat();
+ }
}
@Before
public void setup() throws Exception {
+ Assume.assumeTrue(JavaScriptSandbox.isSupported());
mAdSelectionClient =
new AdSelectionClient(sContext);
mCustomAudienceClient =
@@ -211,8 +221,11 @@
@Test
public void testFledgeAuctionSelectionFlow_overall_Success() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -255,8 +268,11 @@
@Test
public void testAdSelection_etldViolation_failure() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -310,8 +326,11 @@
@Test
public void testReportImpression_etldViolation_failure() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -379,8 +398,11 @@
@Test
public void testAdSelection_skipAdsMalformedBiddingLogic_success() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -432,8 +454,11 @@
@Test
public void testAdSelection_malformedScoringLogic_failure() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -485,8 +510,11 @@
@Test
public void testAdSelection_skipAdsFailedGettingBiddingLogic_success() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -536,8 +564,11 @@
@Test
public void testAdSelection_errorGettingScoringLogic_failure() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -594,8 +625,11 @@
@Test
public void testAdSelectionFlow_skipNonActivatedCA_Success() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -648,8 +682,11 @@
@Test
public void testAdSelectionFlow_skipExpiredCA_Success() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -708,8 +745,11 @@
@Test
public void testAdSelectionFlow_skipCAsThatTimeoutDuringBidding_Success() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
@@ -759,8 +799,11 @@
@Test
public void testAdSelection_overallTimeout_Failure() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
List<Double> bidsForBuyer1 = ImmutableList.of(1.1, 2.2);
List<Double> bidsForBuyer2 = ImmutableList.of(4.5, 6.7, 10.0);
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/TestUtil.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/TestUtil.java
index 57e0e98..33988c1 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/TestUtil.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/TestUtil.java
@@ -92,6 +92,7 @@
public void overrideAllowlists(boolean override) {
String overrideStr = override ? "*" : "null";
runShellCommand("device_config put adservices ppapi_app_allow_list " + overrideStr);
+ runShellCommand("device_config put adservices msmt_api_app_allow_list " + overrideStr);
runShellCommand("device_config put adservices ppapi_app_signature_allow_list "
+ overrideStr);
runShellCommand(
@@ -114,6 +115,18 @@
}
}
+ public void enableBackCompat() {
+ runShellCommand("device_config put adservices enable_back_compat true");
+ runShellCommand("device_config put adservices consent_source_of_truth 3");
+ runShellCommand("device_config put adservices blocked_topics_source_of_truth 3");
+ }
+
+ public void disableBackCompat() {
+ runShellCommand("device_config put adservices enable_back_compat false");
+ runShellCommand("device_config put adservices consent_source_of_truth null");
+ runShellCommand("device_config put adservices blocked_topics_source_of_truth null");
+ }
+
// Override measurement related kill switch to ignore the effect of actual PH values.
// If isOverride = true, override measurement related kill switch to OFF to allow adservices
// If isOverride = false, override measurement related kill switch to meaningless value so that
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/adid/AdIdManagerTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/adid/AdIdManagerTest.java
index c35cb46..c7be1d1 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/adid/AdIdManagerTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/adid/AdIdManagerTest.java
@@ -19,7 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import androidx.privacysandbox.ads.adservices.adid.AdId;
-import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo;
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil;
import androidx.privacysandbox.ads.adservices.java.adid.AdIdManagerFutures;
import androidx.privacysandbox.ads.adservices.java.endtoend.TestUtil;
import androidx.test.core.app.ApplicationProvider;
@@ -63,8 +63,11 @@
@Test
public void testAdId() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
AdIdManagerFutures adIdManager =
AdIdManagerFutures.from(ApplicationProvider.getApplicationContext());
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java
index ecebc1e..fb2fa2f 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/appsetid/AppSetIdManagerTest.java
@@ -19,7 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import androidx.privacysandbox.ads.adservices.appsetid.AppSetId;
-import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo;
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil;
import androidx.privacysandbox.ads.adservices.java.appsetid.AppSetIdManagerFutures;
import androidx.privacysandbox.ads.adservices.java.endtoend.TestUtil;
import androidx.test.core.app.ApplicationProvider;
@@ -60,8 +60,11 @@
@Test
public void testAppSetId() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
AppSetIdManagerFutures appSetIdManager =
AppSetIdManagerFutures.from(ApplicationProvider.getApplicationContext());
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/measurement/MeasurementManagerTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/measurement/MeasurementManagerTest.java
index 7bc4ea9..c43168e 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/measurement/MeasurementManagerTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/measurement/MeasurementManagerTest.java
@@ -22,7 +22,7 @@
import android.net.Uri;
-import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo;
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil;
import androidx.privacysandbox.ads.adservices.java.endtoend.TestUtil;
import androidx.privacysandbox.ads.adservices.java.measurement.MeasurementManagerFutures;
import androidx.privacysandbox.ads.adservices.measurement.DeletionRequest;
@@ -47,6 +47,7 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+@SuppressWarnings("NewApi")
@RunWith(JUnit4.class)
@SdkSuppress(minSdkVersion = 28) // API 28 required for device_config used by this test
// TODO: Consider refactoring so that we're not duplicating code.
@@ -78,6 +79,9 @@
mTestUtil.overrideDisableMeasurementEnrollmentCheck("1");
mMeasurementManager =
MeasurementManagerFutures.from(ApplicationProvider.getApplicationContext());
+ if (VersionCompatUtil.INSTANCE.isSWithMinExtServicesVersion(9)) {
+ mTestUtil.enableBackCompat();
+ }
// Put in a short sleep to make sure the updated config propagates
// before starting the tests
@@ -92,14 +96,21 @@
mTestUtil.overrideMeasurementKillSwitches(false);
mTestUtil.overrideAdIdKillSwitch(false);
mTestUtil.overrideDisableMeasurementEnrollmentCheck("0");
+ if (VersionCompatUtil.INSTANCE.isSWithMinExtServicesVersion(9)) {
+ mTestUtil.disableBackCompat();
+ }
+
// Cool-off rate limiter
TimeUnit.SECONDS.sleep(1);
}
@Test
public void testRegisterSource_NoServerSetup_NoErrors() throws Exception {
- // Skip the test if SDK extension 5 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 5);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 5,
+ /* minExtServicesVersion=*/ 9));
assertThat(mMeasurementManager.registerSourceAsync(
SOURCE_REGISTRATION_URI,
@@ -109,8 +120,12 @@
@Test
public void testRegisterAppSources_NoServerSetup_NoErrors() throws Exception {
+ // Skip the test if the right SDK extension is not present
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 5,
+ /* minExtServicesVersion=*/ 9));
// Skip the test if SDK extension 5 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 5);
SourceRegistrationRequest request =
new SourceRegistrationRequest.Builder(
@@ -122,18 +137,23 @@
@Test
public void testRegisterTrigger_NoServerSetup_NoErrors() throws Exception {
- // Skip the test if SDK extension 5 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 5);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 5,
+ /* minExtServicesVersion=*/ 9));
assertThat(mMeasurementManager.registerTriggerAsync(TRIGGER_REGISTRATION_URI).get())
.isNotNull();
}
@Test
- @SdkSuppress(minSdkVersion = 33)
public void registerWebSource_NoErrors() throws Exception {
- // Skip the test if SDK extension 5 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 5);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 5,
+ /* minExtServicesVersion=*/ 9));
WebSourceParams webSourceParams =
new WebSourceParams(SOURCE_REGISTRATION_URI, false);
@@ -152,10 +172,12 @@
}
@Test
- @SdkSuppress(minSdkVersion = 33)
public void registerWebTrigger_NoErrors() throws Exception {
- // Skip the test if SDK extension 5 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 5);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 5,
+ /* minExtServicesVersion=*/ 9));
WebTriggerParams webTriggerParams =
new WebTriggerParams(TRIGGER_REGISTRATION_URI, false);
@@ -169,11 +191,12 @@
}
@Test
- @SdkSuppress(minSdkVersion = 33)
public void testDeleteRegistrations_withRequest_withNoRange_withCallback_NoErrors()
throws Exception {
// Skip the test if SDK extension 5 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 5);
+ // This test should not run for back compat because it depends on adServices running in
+ // system server
+ Assume.assumeTrue(VersionCompatUtil.INSTANCE.isTPlusWithMinAdServicesVersion(5));
DeletionRequest deletionRequest =
new DeletionRequest.Builder(
@@ -187,11 +210,13 @@
}
@Test
- @SdkSuppress(minSdkVersion = 33)
public void testDeleteRegistrations_withRequest_withEmptyLists_withRange_withCallback_NoErrors()
throws Exception {
- // Skip the test if SDK extension 5 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 5);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 5,
+ /* minExtServicesVersion=*/ 9));
DeletionRequest deletionRequest =
new DeletionRequest.Builder(
@@ -207,11 +232,13 @@
}
@Test
- @SdkSuppress(minSdkVersion = 33)
public void testDeleteRegistrations_withRequest_withInvalidArguments_withCallback_hasError()
throws Exception {
- // Skip the test if SDK extension 5 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 5);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 5,
+ /* minExtServicesVersion=*/ 9));
DeletionRequest deletionRequest =
new DeletionRequest.Builder(
@@ -230,10 +257,12 @@
}
@Test
- @SdkSuppress(minSdkVersion = 33)
public void testMeasurementApiStatus_returnResultStatus() throws Exception {
- // Skip the test if SDK extension 5 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 5);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 5,
+ /* minExtServicesVersion=*/ 9));
int result = mMeasurementManager.getMeasurementApiStatusAsync().get();
assertThat(result).isEqualTo(1);
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/topics/TopicsManagerTest.java b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/topics/TopicsManagerTest.java
index 266394a..9b46fff 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/topics/TopicsManagerTest.java
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/endtoend/topics/TopicsManagerTest.java
@@ -18,7 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
-import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo;
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil;
import androidx.privacysandbox.ads.adservices.java.endtoend.TestUtil;
import androidx.privacysandbox.ads.adservices.java.topics.TopicsManagerFutures;
import androidx.privacysandbox.ads.adservices.topics.GetTopicsRequest;
@@ -73,6 +73,10 @@
mTestUtil.shouldForceUseBundledFiles(true);
// Enable verbose logging.
mTestUtil.enableVerboseLogging();
+
+ if (VersionCompatUtil.INSTANCE.isSWithMinExtServicesVersion(9)) {
+ mTestUtil.enableBackCompat();
+ }
}
@After
@@ -84,13 +88,19 @@
mTestUtil.overrideAllowlists(false);
mTestUtil.enableEnrollmentCheck(false);
mTestUtil.shouldForceUseBundledFiles(false);
+ if (VersionCompatUtil.INSTANCE.isSWithMinExtServicesVersion(9)) {
+ mTestUtil.disableBackCompat();
+ }
}
@Ignore // b/278931615
@Test
public void testTopicsManager_runClassifier() throws Exception {
- // Skip the test if SDK extension 4 is not present.
- Assume.assumeTrue(AdServicesInfo.INSTANCE.version() >= 4);
+ // Skip the test if the right SDK extension is not present.
+ Assume.assumeTrue(
+ VersionCompatUtil.INSTANCE.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9));
TopicsManagerFutures topicsManager =
TopicsManagerFutures.from(ApplicationProvider.getApplicationContext());
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/measurement/MeasurementManagerFuturesTest.kt b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/measurement/MeasurementManagerFuturesTest.kt
index 0106e76..cb58c43 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/measurement/MeasurementManagerFuturesTest.kt
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/measurement/MeasurementManagerFuturesTest.kt
@@ -21,10 +21,9 @@
import android.net.Uri
import android.os.Looper
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
import android.view.InputEvent
-import androidx.annotation.RequiresExtension
import androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil
import androidx.privacysandbox.ads.adservices.java.measurement.MeasurementManagerFutures.Companion.from
import androidx.privacysandbox.ads.adservices.measurement.DeletionRequest
import androidx.privacysandbox.ads.adservices.measurement.SourceRegistrationRequest
@@ -36,6 +35,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth.assertThat
import java.time.Instant
import java.util.concurrent.ExecutionException
@@ -46,6 +47,7 @@
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.Test
@@ -61,6 +63,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
@SmallTest
@SuppressWarnings("NewApi")
@@ -68,27 +71,46 @@
@SdkSuppress(minSdkVersion = 30)
class MeasurementManagerFuturesTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdExtServicesSdkExtVersion = VersionCompatUtil.isSWithMinExtServicesVersion(9)
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.measurement.MeasurementManager::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testMeasurementOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 4", sdkExtVersion < 5)
+ Assume.assumeFalse("maxSdkVersion = API 33 ext 4 or API 31/32 ext 8",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion=*/ 5,
+ /* minExtServicesVersion=*/ 9))
assertThat(from(mContext)).isEqualTo(null)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testDeleteRegistrationsAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 5,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val mMeasurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val managerCompat = from(mContext)
// Set up the request.
@@ -98,7 +120,7 @@
assertNotEquals(Looper.myLooper(), Looper.getMainLooper())
null
}
- doAnswer(answer).`when`(measurementManager).deleteRegistrations(any(), any(), any())
+ doAnswer(answer).`when`(mMeasurementManager).deleteRegistrations(any(), any(), any())
// Actually invoke the compat code.
val request = DeletionRequest(
@@ -115,28 +137,30 @@
val captor = ArgumentCaptor.forClass(
android.adservices.measurement.DeletionRequest::class.java
)
- verify(measurementManager).deleteRegistrations(captor.capture(), any(), any())
+ verify(mMeasurementManager).deleteRegistrations(captor.capture(), any(), any())
// Verify that the request that the compat code makes to the platform is correct.
verifyDeletionRequest(captor.value)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testRegisterSourceAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 5,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
+ val mMeasurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val inputEvent = mock(InputEvent::class.java)
- val measurementManager = mockMeasurementManager(mContext)
val managerCompat = from(mContext)
+
val answer = { args: InvocationOnMock ->
assertNotEquals(Looper.myLooper(), Looper.getMainLooper())
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(3)
receiver.onResult(Object())
null
}
- doAnswer(answer).`when`(measurementManager).registerSource(any(), any(), any(), any())
+ doAnswer(answer).`when`(mMeasurementManager).registerSource(any(), any(), any(), any())
// Actually invoke the compat code.
managerCompat!!.registerSourceAsync(uri1, inputEvent).get()
@@ -144,7 +168,7 @@
// Verify that the compat code was invoked correctly.
val captor1 = ArgumentCaptor.forClass(Uri::class.java)
val captor2 = ArgumentCaptor.forClass(InputEvent::class.java)
- verify(measurementManager).registerSource(
+ verify(mMeasurementManager).registerSource(
captor1.capture(),
captor2.capture(),
any(),
@@ -156,27 +180,29 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testRegisterTriggerAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 5,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val mMeasurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val managerCompat = from(mContext)
+
val answer = { args: InvocationOnMock ->
assertNotEquals(Looper.myLooper(), Looper.getMainLooper())
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(2)
receiver.onResult(Object())
null
}
- doAnswer(answer).`when`(measurementManager).registerTrigger(any(), any(), any())
+ doAnswer(answer).`when`(mMeasurementManager).registerTrigger(any(), any(), any())
// Actually invoke the compat code.
managerCompat!!.registerTriggerAsync(uri1).get()
// Verify that the compat code was invoked correctly.
val captor1 = ArgumentCaptor.forClass(Uri::class.java)
- verify(measurementManager).registerTrigger(
+ verify(mMeasurementManager).registerTrigger(
captor1.capture(),
any(),
any())
@@ -186,20 +212,22 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testRegisterWebSourceAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 5,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val mMeasurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val managerCompat = from(mContext)
+
val answer = { args: InvocationOnMock ->
assertNotEquals(Looper.myLooper(), Looper.getMainLooper())
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(2)
receiver.onResult(Object())
null
}
- doAnswer(answer).`when`(measurementManager).registerWebSource(any(), any(), any())
+ doAnswer(answer).`when`(mMeasurementManager).registerWebSource(any(), any(), any())
val request = WebSourceRegistrationRequest.Builder(
listOf(WebSourceParams(uri2, false)), uri1)
@@ -212,7 +240,7 @@
// Verify that the compat code was invoked correctly.
val captor1 = ArgumentCaptor.forClass(
android.adservices.measurement.WebSourceRegistrationRequest::class.java)
- verify(measurementManager).registerWebSource(
+ verify(mMeasurementManager).registerWebSource(
captor1.capture(),
any(),
any())
@@ -226,20 +254,22 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testRegisterWebTriggerAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 5,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val mMeasurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val managerCompat = from(mContext)
+
val answer = { args: InvocationOnMock ->
assertNotEquals(Looper.myLooper(), Looper.getMainLooper())
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(2)
receiver.onResult(Object())
null
}
- doAnswer(answer).`when`(measurementManager).registerWebTrigger(any(), any(), any())
+ doAnswer(answer).`when`(mMeasurementManager).registerWebTrigger(any(), any(), any())
val request = WebTriggerRegistrationRequest(listOf(WebTriggerParams(uri1, false)), uri2)
@@ -249,7 +279,7 @@
// Verify that the compat code was invoked correctly.
val captor1 = ArgumentCaptor.forClass(
android.adservices.measurement.WebTriggerRegistrationRequest::class.java)
- verify(measurementManager).registerWebTrigger(
+ verify(mMeasurementManager).registerWebTrigger(
captor1.capture(),
any(),
any())
@@ -263,13 +293,15 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testMeasurementApiStatusAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 5,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val mMeasurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val managerCompat = from(mContext)
+
val state = MeasurementManager.MEASUREMENT_API_STATE_DISABLED
val answer = { args: InvocationOnMock ->
assertNotEquals(Looper.myLooper(), Looper.getMainLooper())
@@ -277,14 +309,14 @@
receiver.onResult(state)
null
}
- doAnswer(answer).`when`(measurementManager).getMeasurementApiStatus(any(), any())
+ doAnswer(answer).`when`(mMeasurementManager).getMeasurementApiStatus(any(), any())
// Actually invoke the compat code.
val result = managerCompat!!.getMeasurementApiStatusAsync()
result.get()
// Verify that the compat code was invoked correctly.
- verify(measurementManager).getMeasurementApiStatus(any(), any())
+ verify(mMeasurementManager).getMeasurementApiStatus(any(), any())
// Verify that the result.
assertThat(result.get() == state)
@@ -292,21 +324,23 @@
@ExperimentalFeatures.RegisterSourceOptIn
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testRegisterSourceAsync_allSuccess() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 5,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
+ val mMeasurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val inputEvent = mock(InputEvent::class.java)
- val measurementManager = mockMeasurementManager(mContext)
val managerCompat = from(mContext)
+
val successCallback = { args: InvocationOnMock ->
assertNotEquals(Looper.myLooper(), Looper.getMainLooper())
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(3)
receiver.onResult(Object())
null
}
- doAnswer(successCallback).`when`(measurementManager)
+ doAnswer(successCallback).`when`(mMeasurementManager)
.registerSource(any(), any(), any(), any())
// Actually invoke the compat code.
@@ -316,12 +350,12 @@
managerCompat!!.registerSourceAsync(request).get()
// Verify that the compat code was invoked correctly.
- verify(measurementManager).registerSource(
+ verify(mMeasurementManager).registerSource(
eq(uri1),
eq(inputEvent),
any(Executor::class.java),
any())
- verify(measurementManager).registerSource(
+ verify(mMeasurementManager).registerSource(
eq(uri2),
eq(inputEvent),
any(Executor::class.java),
@@ -329,15 +363,17 @@
}
@ExperimentalFeatures.RegisterSourceOptIn
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
@Test
fun testRegisterSource_15thOf20Fails_atLeast15thExecutes() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 5,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val mMeasurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val mockInputEvent = mock(InputEvent::class.java)
val managerCompat = from(mContext)
+
val successCallback = { args: InvocationOnMock ->
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(3)
receiver.onResult(Object())
@@ -354,10 +390,10 @@
val uris = (1..20).map { i ->
val uri = Uri.parse("www.uri$i.com")
if (i == 15) {
- doAnswer(errorCallback).`when`(measurementManager)
+ doAnswer(errorCallback).`when`(mMeasurementManager)
.registerSource(eq(uri), any(), any(), any())
} else {
- doAnswer(successCallback).`when`(measurementManager)
+ doAnswer(successCallback).`when`(mMeasurementManager)
.registerSource(eq(uri), any(), any(), any())
}
uri
@@ -382,13 +418,13 @@
// registerSource gets called 1-20 times. We cannot predict the exact number because
// uri15 would crash asynchronously. Other uris may succeed and those threads on default
// dispatcher won't crash.
- verify(measurementManager, atLeastOnce()).registerSource(
+ verify(mMeasurementManager, atLeastOnce()).registerSource(
any(),
eq(mockInputEvent),
any(),
any()
)
- verify(measurementManager, atMost(20)).registerSource(
+ verify(mMeasurementManager, atMost(20)).registerSource(
any(),
eq(mockInputEvent),
any(),
@@ -397,17 +433,25 @@
}
@SdkSuppress(minSdkVersion = 30)
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
companion object {
private val uri1: Uri = Uri.parse("www.abc.com")
private val uri2: Uri = Uri.parse("http://www.xyz.com")
private lateinit var mContext: Context
- private fun mockMeasurementManager(spyContext: Context): MeasurementManager {
+ private fun mockMeasurementManager(
+ spyContext: Context,
+ isExtServices: Boolean
+ ): MeasurementManager {
val measurementManager = mock(MeasurementManager::class.java)
- `when`(spyContext.getSystemService(MeasurementManager::class.java))
- .thenReturn(measurementManager)
+ // mock the .get() method if using extServices version, otherwise mock getSystemService
+ if (isExtServices) {
+ `when`(android.adservices.measurement.MeasurementManager.get(any()))
+ .thenReturn(measurementManager)
+ } else {
+ `when`(spyContext.getSystemService(MeasurementManager::class.java))
+ .thenReturn(measurementManager)
+ }
return measurementManager
}
diff --git a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/topics/TopicsManagerFuturesTest.kt b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/topics/TopicsManagerFuturesTest.kt
index c44c32f..6d84365 100644
--- a/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/topics/TopicsManagerFuturesTest.kt
+++ b/privacysandbox/ads/ads-adservices-java/src/androidTest/java/androidx/privacysandbox/ads/adservices/java/topics/TopicsManagerFuturesTest.kt
@@ -20,8 +20,7 @@
import android.adservices.topics.TopicsManager
import android.content.Context
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
-import androidx.annotation.RequiresExtension
+import androidx.privacysandbox.ads.adservices.java.VersionCompatUtil
import androidx.privacysandbox.ads.adservices.java.topics.TopicsManagerFutures.Companion.from
import androidx.privacysandbox.ads.adservices.topics.GetTopicsRequest
import androidx.privacysandbox.ads.adservices.topics.GetTopicsResponse
@@ -29,8 +28,11 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.ListenableFuture
+import org.junit.After
import org.junit.Assert
import org.junit.Assume
import org.junit.Before
@@ -44,6 +46,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
@SmallTest
@SuppressWarnings("NewApi")
@@ -51,43 +54,65 @@
@SdkSuppress(minSdkVersion = 30)
class TopicsManagerFuturesTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdExtServicesSdkExtVersion = VersionCompatUtil.isSWithMinExtServicesVersion(9)
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.topics.TopicsManager::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testTopicsOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeFalse("maxSdkVersion = API 33 ext 3 or API 31/32 ext 8",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion=*/ 4,
+ /* minExtServicesVersion=*/ 9))
assertThat(from(mContext)).isEqualTo(null)
}
@Test
@SuppressWarnings("NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testTopicsAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 4,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val topicsManager = mockTopicsManager(mContext)
+ val topicsManager = mockTopicsManager(mContext, mValidAdExtServicesSdkExtVersion)
setupTopicsResponse(topicsManager)
val managerCompat = from(mContext)
// Actually invoke the compat code.
- val request =
- GetTopicsRequest.Builder().setAdsSdkName(mSdkName).setShouldRecordObservation(true)
- .build()
+ val request = GetTopicsRequest.Builder()
+ .setAdsSdkName(mSdkName)
+ .setShouldRecordObservation(true)
+ .build()
- val result: ListenableFuture<GetTopicsResponse> = managerCompat!!.getTopicsAsync(request)
+ val result: ListenableFuture<GetTopicsResponse> =
+ managerCompat!!.getTopicsAsync(request)
// Verify that the result of the compat call is correct.
verifyResponse(result.get())
// Verify that the compat code was invoked correctly.
- val captor = ArgumentCaptor.forClass(android.adservices.topics.GetTopicsRequest::class.java)
+ val captor = ArgumentCaptor
+ .forClass(android.adservices.topics.GetTopicsRequest::class.java)
verify(topicsManager).getTopics(captor.capture(), any(), any())
// Verify that the request that the compat code makes to the platform is correct.
@@ -96,12 +121,13 @@
@Test
@SuppressWarnings("NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testTopicsAsyncPreviewSupported() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ VersionCompatUtil.isTestableVersion(
+ /* minAdServicesVersion= */ 5,
+ /* minExtServicesVersion=*/ 9))
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val topicsManager = mockTopicsManager(mContext)
+ val topicsManager = mockTopicsManager(mContext, mValidAdExtServicesSdkExtVersion)
setupTopicsResponse(topicsManager)
val managerCompat = from(mContext)
@@ -110,13 +136,15 @@
GetTopicsRequest.Builder().setAdsSdkName(mSdkName).setShouldRecordObservation(false)
.build()
- val result: ListenableFuture<GetTopicsResponse> = managerCompat!!.getTopicsAsync(request)
+ val result: ListenableFuture<GetTopicsResponse> =
+ managerCompat!!.getTopicsAsync(request)
// Verify that the result of the compat call is correct.
verifyResponse(result.get())
// Verify that the compat code was invoked correctly.
- val captor = ArgumentCaptor.forClass(android.adservices.topics.GetTopicsRequest::class.java)
+ val captor =
+ ArgumentCaptor.forClass(android.adservices.topics.GetTopicsRequest::class.java)
verify(topicsManager).getTopics(captor.capture(), any(), any())
// Verify that the request that the compat code makes to the platform is correct.
@@ -127,14 +155,18 @@
private lateinit var mContext: Context
private val mSdkName: String = "sdk1"
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
- private fun mockTopicsManager(spyContext: Context): TopicsManager {
+ private fun mockTopicsManager(spyContext: Context, isExtServices: Boolean): TopicsManager {
val topicsManager = mock(TopicsManager::class.java)
- `when`(spyContext.getSystemService(TopicsManager::class.java)).thenReturn(topicsManager)
+ // mock the .get() method if using extServices version, otherwise mock getSystemService
+ if (isExtServices) {
+ `when`(TopicsManager.get(any())).thenReturn(topicsManager)
+ } else {
+ `when`(spyContext.getSystemService(TopicsManager::class.java))
+ .thenReturn(topicsManager)
+ }
return topicsManager
}
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
private fun setupTopicsResponse(topicsManager: TopicsManager) {
// Set up the response that TopicsManager will return when the compat code calls it.
val topic1 = Topic(1, 1, 1)
@@ -152,7 +184,6 @@
)
}
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
private fun verifyRequest(topicsRequest: android.adservices.topics.GetTopicsRequest) {
// Set up the request that we expect the compat code to invoke.
val expectedRequest =
@@ -161,7 +192,6 @@
Assert.assertEquals(expectedRequest.adsSdkName, topicsRequest.adsSdkName)
}
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
private fun verifyRequestPreviewApi(
topicsRequest: android.adservices.topics.GetTopicsRequest
) {
@@ -176,7 +206,6 @@
)
}
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
private fun verifyResponse(getTopicsResponse: GetTopicsResponse) {
Assert.assertEquals(2, getTopicsResponse.topics.size)
val topic1 = getTopicsResponse.topics[0]
diff --git a/privacysandbox/ads/ads-adservices/build.gradle b/privacysandbox/ads/ads-adservices/build.gradle
index 866cc02..1c3fa23 100644
--- a/privacysandbox/ads/ads-adservices/build.gradle
+++ b/privacysandbox/ads/ads-adservices/build.gradle
@@ -41,6 +41,7 @@
androidTestImplementation(libs.mockitoCore4, excludes.bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation(libs.dexmakerMockitoInline, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+ androidTestImplementation(libs.dexmakerMockitoInlineExtended)
}
android {
diff --git a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerTest.kt b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerTest.kt
index 197f46b..ce7e661 100644
--- a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerTest.kt
+++ b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerTest.kt
@@ -20,14 +20,18 @@
import android.os.OutcomeReceiver
import android.os.ext.SdkExtensions
import androidx.annotation.RequiresExtension
+import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
+import org.junit.After
import org.junit.Assert
-import org.junit.Assume.assumeTrue
+import org.junit.Assume
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,27 +48,42 @@
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = 30)
class AdIdManagerTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdServicesSdkExtVersion = AdServicesInfo.adServicesVersion() >= 4
+ private val mValidAdExtServicesSdkExtVersion = AdServicesInfo.extServicesVersion() >= 9
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.adid.AdIdManager::class.java)
+ .startMocking();
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testAdIdOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
- assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeTrue("maxSdkVersion = API 33 ext 3", !mValidAdServicesSdkExtVersion)
+ Assume.assumeTrue("maxSdkVersion = API 31/32 ext 8", !mValidAdExtServicesSdkExtVersion)
assertThat(AdIdManager.obtain(mContext)).isEqualTo(null)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testAdIdAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val adIdManager = mockAdIdManager(mContext)
+ val adIdManager = mockAdIdManager(mContext, mValidAdExtServicesSdkExtVersion)
setupResponse(adIdManager)
val managerCompat = AdIdManager.obtain(mContext)
@@ -85,10 +104,19 @@
companion object {
private lateinit var mContext: Context
- private fun mockAdIdManager(spyContext: Context): android.adservices.adid.AdIdManager {
+ private fun mockAdIdManager(
+ spyContext: Context,
+ isExtServices: Boolean
+ ): android.adservices.adid.AdIdManager {
val adIdManager = mock(android.adservices.adid.AdIdManager::class.java)
- `when`(spyContext.getSystemService(android.adservices.adid.AdIdManager::class.java))
- .thenReturn(adIdManager)
+ // only mock the .get() method if using extServices version
+ if (isExtServices) {
+ `when`(android.adservices.adid.AdIdManager.get(any()))
+ .thenReturn(adIdManager)
+ } else {
+ `when`(spyContext.getSystemService(android.adservices.adid.AdIdManager::class.java))
+ .thenReturn(adIdManager)
+ }
return adIdManager
}
diff --git a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerTest.kt b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerTest.kt
index 8d71ea2..8f4b4a24 100644
--- a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerTest.kt
+++ b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerTest.kt
@@ -20,17 +20,19 @@
import android.content.Context
import android.net.Uri
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
-import androidx.annotation.RequiresExtension
import androidx.privacysandbox.ads.adservices.adselection.AdSelectionManager.Companion.obtain
import androidx.privacysandbox.ads.adservices.common.AdSelectionSignals
import androidx.privacysandbox.ads.adservices.common.AdTechIdentifier
+import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
+import org.junit.After
import org.junit.Assert
import org.junit.Assume
import org.junit.Before
@@ -44,33 +46,50 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
@SmallTest
@SuppressWarnings("NewApi")
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = 30)
class AdSelectionManagerTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdServicesSdkExtVersion = AdServicesInfo.adServicesVersion() >= 4
+ private val mValidAdExtServicesSdkExtVersion = AdServicesInfo.extServicesVersion() >= 9
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = mockitoSession()
+ .mockStatic(android.adservices.adselection.AdSelectionManager::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testAdSelectionOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeTrue("maxSdkVersion = API 33 ext 3", !mValidAdServicesSdkExtVersion)
+ Assume.assumeTrue("maxSdkVersion = API 31/32 ext 8", !mValidAdExtServicesSdkExtVersion)
assertThat(obtain(mContext)).isEqualTo(null)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testSelectAds() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val adSelectionManager = mockAdSelectionManager(mContext)
+ val adSelectionManager = mockAdSelectionManager(mContext, mValidAdExtServicesSdkExtVersion)
setupAdSelectionResponse(adSelectionManager)
val managerCompat = obtain(mContext)
@@ -92,13 +111,13 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testReportImpression() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val adSelectionManager = mockAdSelectionManager(mContext)
+ val adSelectionManager = mockAdSelectionManager(mContext, mValidAdExtServicesSdkExtVersion)
setupAdSelectionResponse(adSelectionManager)
+
val managerCompat = obtain(mContext)
val reportImpressionRequest = ReportImpressionRequest(adSelectionId, adSelectionConfig)
@@ -117,7 +136,6 @@
}
@SdkSuppress(minSdkVersion = 30)
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
companion object {
private lateinit var mContext: Context
private const val adSelectionId = 1234L
@@ -146,13 +164,20 @@
private val renderUri = Uri.parse("render-uri.com")
private fun mockAdSelectionManager(
- spyContext: Context
+ spyContext: Context,
+ isExtServices: Boolean
): android.adservices.adselection.AdSelectionManager {
val adSelectionManager =
mock(android.adservices.adselection.AdSelectionManager::class.java)
`when`(spyContext.getSystemService(
android.adservices.adselection.AdSelectionManager::class.java))
.thenReturn(adSelectionManager)
+ // only mock the .get() method if using extServices version
+ if (isExtServices) {
+ `when`(android.adservices.adselection.AdSelectionManager.get(any()))
+ .thenReturn(adSelectionManager)
+ }
+
return adSelectionManager
}
diff --git a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerTest.kt b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerTest.kt
index f3f3e99..8167b8f 100644
--- a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerTest.kt
+++ b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerTest.kt
@@ -20,12 +20,16 @@
import android.os.OutcomeReceiver
import android.os.ext.SdkExtensions
import androidx.annotation.RequiresExtension
+import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
+import org.junit.After
import org.junit.Assert
import org.junit.Assume
import org.junit.Before
@@ -44,28 +48,42 @@
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = 30)
class AppSetIdManagerTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdServicesSdkExtVersion = AdServicesInfo.adServicesVersion() >= 4
+ private val mValidAdExtServicesSdkExtVersion = AdServicesInfo.extServicesVersion() >= 9
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.appsetid.AppSetIdManager::class.java)
+ .startMocking();
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testAppSetIdOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeTrue("maxSdkVersion = API 33 ext 3", !mValidAdServicesSdkExtVersion)
+ Assume.assumeTrue("maxSdkVersion = API 31/32 ext 8", !mValidAdExtServicesSdkExtVersion)
assertThat(AppSetIdManager.obtain(mContext)).isEqualTo(null)
}
@Test
- @SuppressWarnings("NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testAppSetIdAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val appSetIdManager = mockAppSetIdManager(mContext)
+ val appSetIdManager = mockAppSetIdManager(mContext, mValidAdExtServicesSdkExtVersion)
setupResponse(appSetIdManager)
val managerCompat = AppSetIdManager.obtain(mContext)
@@ -87,12 +105,19 @@
private lateinit var mContext: Context
private fun mockAppSetIdManager(
- spyContext: Context
+ spyContext: Context,
+ isExtServices: Boolean
): android.adservices.appsetid.AppSetIdManager {
val appSetIdManager = mock(android.adservices.appsetid.AppSetIdManager::class.java)
- `when`(spyContext.getSystemService(
- android.adservices.appsetid.AppSetIdManager::class.java))
- .thenReturn(appSetIdManager)
+ // only mock the .get() method if using extServices version
+ if (isExtServices) {
+ `when`(android.adservices.appsetid.AppSetIdManager.get(any()))
+ .thenReturn(appSetIdManager)
+ } else {
+ `when`(spyContext.getSystemService(
+ android.adservices.appsetid.AppSetIdManager::class.java))
+ .thenReturn(appSetIdManager)
+ }
return appSetIdManager
}
diff --git a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerTest.kt b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerTest.kt
index a107e7d..53d4f16 100644
--- a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerTest.kt
+++ b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerTest.kt
@@ -20,19 +20,21 @@
import android.content.Context
import android.net.Uri
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
-import androidx.annotation.RequiresExtension
import androidx.privacysandbox.ads.adservices.common.AdData
import androidx.privacysandbox.ads.adservices.common.AdSelectionSignals
import androidx.privacysandbox.ads.adservices.common.AdTechIdentifier
import androidx.privacysandbox.ads.adservices.customaudience.CustomAudienceManager.Companion.obtain
+import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth
import java.time.Instant
import kotlinx.coroutines.runBlocking
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.Test
@@ -45,6 +47,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
@SmallTest
@SuppressWarnings("NewApi")
@@ -52,27 +55,44 @@
@SdkSuppress(minSdkVersion = 30)
class CustomAudienceManagerTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdServicesSdkExtVersion = AdServicesInfo.adServicesVersion() >= 4
+ private val mValidAdExtServicesSdkExtVersion = AdServicesInfo.extServicesVersion() >= 9
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.customaudience.CustomAudienceManager::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeTrue("maxSdkVersion = API 33 ext 3", !mValidAdServicesSdkExtVersion)
+ Assume.assumeTrue("maxSdkVersion = API 31/32 ext 8", !mValidAdExtServicesSdkExtVersion)
Truth.assertThat(obtain(mContext)).isEqualTo(null)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testJoinCustomAudience() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val customAudienceManager = mockCustomAudienceManager(mContext)
+ val customAudienceManager =
+ mockCustomAudienceManager(mContext, mValidAdExtServicesSdkExtVersion)
setupResponse(customAudienceManager)
val managerCompat = obtain(mContext)
@@ -99,12 +119,12 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testLeaveCustomAudience() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val customAudienceManager = mockCustomAudienceManager(mContext)
+ val customAudienceManager =
+ mockCustomAudienceManager(mContext, mValidAdExtServicesSdkExtVersion)
setupResponse(customAudienceManager)
val managerCompat = obtain(mContext)
@@ -125,7 +145,6 @@
}
@SdkSuppress(minSdkVersion = 30)
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
companion object {
private lateinit var mContext: Context
private val uri: Uri = Uri.parse("abc.com")
@@ -139,10 +158,17 @@
private const val metadata = "metadata"
private val ads: List<AdData> = listOf(AdData(uri, metadata))
- private fun mockCustomAudienceManager(spyContext: Context): CustomAudienceManager {
+ private fun mockCustomAudienceManager(
+ spyContext: Context,
+ isExtServices: Boolean
+ ): CustomAudienceManager {
val customAudienceManager = mock(CustomAudienceManager::class.java)
`when`(spyContext.getSystemService(CustomAudienceManager::class.java))
.thenReturn(customAudienceManager)
+ // only mock the .get() method if using extServices version
+ if (isExtServices) {
+ `when`(CustomAudienceManager.get(any())).thenReturn(customAudienceManager)
+ }
return customAudienceManager
}
diff --git a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerTest.kt b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerTest.kt
index 1e0a826..1b9f302 100644
--- a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerTest.kt
+++ b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerTest.kt
@@ -20,20 +20,21 @@
import android.content.Context
import android.net.Uri
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
import android.view.InputEvent
-import androidx.annotation.RequiresExtension
import androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures
+import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
import androidx.privacysandbox.ads.adservices.measurement.MeasurementManager.Companion.obtain
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import androidx.testutils.fail
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth.assertThat
import java.time.Instant
-import kotlin.IllegalArgumentException
import kotlinx.coroutines.runBlocking
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.Test
@@ -49,6 +50,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
@SmallTest
@SuppressWarnings("NewApi")
@@ -56,27 +58,43 @@
@SdkSuppress(minSdkVersion = 30)
class MeasurementManagerTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdServicesSdkExtVersion = AdServicesInfo.adServicesVersion() >= 5
+ private val mValidAdExtServicesSdkExtVersion = AdServicesInfo.extServicesVersion() >= 9
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.measurement.MeasurementManager::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testMeasurementOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 4", sdkExtVersion < 5)
+ Assume.assumeTrue("maxSdkVersion = API 33 ext 4", !mValidAdServicesSdkExtVersion)
+ Assume.assumeTrue("maxSdkVersion = API 31/32 ext 8", !mValidAdExtServicesSdkExtVersion)
assertThat(obtain(mContext)).isEqualTo(null)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testDeleteRegistrations() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val measurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val managerCompat = obtain(mContext)
// Set up the request.
@@ -111,14 +129,14 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testRegisterSource() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
+ val measurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val inputEvent = mock(InputEvent::class.java)
- val measurementManager = mockMeasurementManager(mContext)
val managerCompat = obtain(mContext)
+
val answer = { args: InvocationOnMock ->
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(3)
receiver.onResult(Object())
@@ -146,12 +164,11 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testRegisterTrigger() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val measurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val managerCompat = obtain(mContext)
val answer = { args: InvocationOnMock ->
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(2)
@@ -177,12 +194,11 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testRegisterWebSource() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val measurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val managerCompat = obtain(mContext)
val answer = { args: InvocationOnMock ->
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(2)
@@ -218,15 +234,15 @@
}
@ExperimentalFeatures.RegisterSourceOptIn
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
@Test
fun testRegisterSource_allSuccess() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val measurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val mockInputEvent = mock(InputEvent::class.java)
val managerCompat = obtain(mContext)
+
val successCallback = { args: InvocationOnMock ->
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(3)
receiver.onResult(Object())
@@ -252,15 +268,15 @@
}
@ExperimentalFeatures.RegisterSourceOptIn
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
@Test
fun testRegisterSource_15thOf20Fails_remaining5DoNotExecute() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val measurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val mockInputEvent = mock(InputEvent::class.java)
val managerCompat = obtain(mContext)
+
val successCallback = { args: InvocationOnMock ->
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(3)
receiver.onResult(Object())
@@ -317,12 +333,11 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testRegisterWebTrigger() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
+ val measurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
val managerCompat = obtain(mContext)
val answer = { args: InvocationOnMock ->
val receiver = args.getArgument<OutcomeReceiver<Any, Exception>>(2)
@@ -356,63 +371,33 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testMeasurementApiStatus() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
- val managerCompat = obtain(mContext)
- val state = MeasurementManager.MEASUREMENT_API_STATE_ENABLED
- val answer = { args: InvocationOnMock ->
- val receiver = args.getArgument<OutcomeReceiver<Int, Exception>>(1)
- receiver.onResult(state)
- null
- }
- doAnswer(answer).`when`(measurementManager).getMeasurementApiStatus(any(), any())
-
- // Actually invoke the compat code.
- val actualResult = runBlocking {
- managerCompat!!.getMeasurementApiStatus()
- }
-
- // Verify that the compat code was invoked correctly.
- verify(measurementManager).getMeasurementApiStatus(any(), any())
-
- // Verify that the request that the compat code makes to the platform is correct.
- assertThat(actualResult == state)
+ val measurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
+ callAndVerifyGetMeasurementApiStatus(
+ measurementManager,
+ /* state= */ MeasurementManager.MEASUREMENT_API_STATE_ENABLED,
+ /* expectedResult= */ MeasurementManager.MEASUREMENT_API_STATE_ENABLED)
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testMeasurementApiStatusUnknown() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExtVersion || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val measurementManager = mockMeasurementManager(mContext)
- val managerCompat = obtain(mContext)
- val answer = { args: InvocationOnMock ->
- val receiver = args.getArgument<OutcomeReceiver<Int, Exception>>(1)
- receiver.onResult(6 /* Greater than values returned in SdkExtensions.AD_SERVICES = 5 */)
- null
- }
- doAnswer(answer).`when`(measurementManager).getMeasurementApiStatus(any(), any())
+ val measurementManager = mockMeasurementManager(mContext, mValidAdExtServicesSdkExtVersion)
- // Actually invoke the compat code.
- val actualResult = runBlocking {
- managerCompat!!.getMeasurementApiStatus()
- }
-
- // Verify that the compat code was invoked correctly.
- verify(measurementManager).getMeasurementApiStatus(any(), any())
-
- // Verify that the request that the compat code makes to the platform is correct.
+ // Call with a value greater than values returned in SdkExtensions.AD_SERVICES = 5
// Since the compat code does not know the returned state, it sets it to UNKNOWN.
- assertThat(actualResult == 5)
+ callAndVerifyGetMeasurementApiStatus(
+ measurementManager,
+ /* state= */ 6,
+ /* expectedResult= */ 5)
}
@SdkSuppress(minSdkVersion = 30)
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
companion object {
private val uri1: Uri = Uri.parse("www.abc.com")
@@ -420,13 +405,46 @@
private lateinit var mContext: Context
- private fun mockMeasurementManager(spyContext: Context): MeasurementManager {
+ private fun mockMeasurementManager(
+ spyContext: Context,
+ isExtServices: Boolean
+ ): MeasurementManager {
val measurementManager = mock(MeasurementManager::class.java)
`when`(spyContext.getSystemService(MeasurementManager::class.java))
.thenReturn(measurementManager)
+ // only mock the .get() method if using the extServices version
+ if (isExtServices) {
+ `when`(MeasurementManager.get(any()))
+ .thenReturn(measurementManager)
+ }
return measurementManager
}
+ private fun callAndVerifyGetMeasurementApiStatus(
+ measurementManager: android.adservices.measurement.MeasurementManager,
+ state: Int,
+ expectedResult: Int
+ ) {
+ val managerCompat = obtain(mContext)
+ val answer = { args: InvocationOnMock ->
+ val receiver = args.getArgument<OutcomeReceiver<Int, Exception>>(1)
+ receiver.onResult(state)
+ null
+ }
+ doAnswer(answer).`when`(measurementManager).getMeasurementApiStatus(any(), any())
+
+ // Actually invoke the compat code.
+ val actualResult = runBlocking {
+ managerCompat!!.getMeasurementApiStatus()
+ }
+
+ // Verify that the compat code was invoked correctly.
+ verify(measurementManager).getMeasurementApiStatus(any(), any())
+
+ // Verify that the request that the compat code makes to the platform is correct.
+ assertThat(actualResult == expectedResult)
+ }
+
private fun verifyDeletionRequest(request: android.adservices.measurement.DeletionRequest) {
// Set up the request that we expect the compat code to invoke.
val expectedRequest = android.adservices.measurement.DeletionRequest.Builder()
diff --git a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerTest.kt b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerTest.kt
index d79e94e..82a492b 100644
--- a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerTest.kt
+++ b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerTest.kt
@@ -20,15 +20,17 @@
import android.adservices.topics.TopicsManager
import android.content.Context
import android.os.OutcomeReceiver
-import android.os.ext.SdkExtensions
-import androidx.annotation.RequiresExtension
+import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
import androidx.privacysandbox.ads.adservices.topics.TopicsManager.Companion.obtain
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
+import org.junit.After
import org.junit.Assert
import org.junit.Assume
import org.junit.Before
@@ -42,6 +44,7 @@
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
+import org.mockito.quality.Strictness
@SmallTest
@SuppressWarnings("NewApi")
@@ -49,42 +52,60 @@
@SdkSuppress(minSdkVersion = 30)
class TopicsManagerTest {
+ private var mSession: StaticMockitoSession? = null
+ private val mValidAdServicesSdkExt4Version = AdServicesInfo.adServicesVersion() >= 4
+ private val mValidAdServicesSdkExt5Version = AdServicesInfo.adServicesVersion() >= 5
+ private val mValidAdExtServicesSdkExtVersion = AdServicesInfo.extServicesVersion() >= 9
+
@Before
fun setUp() {
mContext = spy(ApplicationProvider.getApplicationContext<Context>())
+
+ if (mValidAdExtServicesSdkExtVersion) {
+ // setup a mockitoSession to return the mocked manager
+ // when the static method .get() is called
+ mSession = ExtendedMockito.mockitoSession()
+ .mockStatic(android.adservices.topics.TopicsManager::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ }
+ }
+
+ @After
+ fun tearDown() {
+ mSession?.finishMocking()
}
@Test
@SdkSuppress(maxSdkVersion = 33, minSdkVersion = 30)
fun testTopicsOlderVersions() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
-
- Assume.assumeTrue("maxSdkVersion = API 33 ext 3", sdkExtVersion < 4)
+ Assume.assumeTrue("maxSdkVersion = API 33 ext 3", !mValidAdServicesSdkExt4Version)
+ Assume.assumeTrue("maxSdkVersion = API 31/32 ext 8", !mValidAdExtServicesSdkExtVersion)
assertThat(obtain(mContext)).isEqualTo(null)
}
@Test
- @SuppressWarnings("NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
fun testTopicsAsync() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 4 or API 31/32 ext 9",
+ mValidAdServicesSdkExt4Version || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 4", sdkExtVersion >= 4)
- val topicsManager = mockTopicsManager(mContext)
+ val topicsManager = mockTopicsManager(mContext, mValidAdExtServicesSdkExtVersion)
setupTopicsResponse(topicsManager)
val managerCompat = obtain(mContext)
// Actually invoke the compat code.
val result = runBlocking {
- val request =
- GetTopicsRequest.Builder().setAdsSdkName(mSdkName).setShouldRecordObservation(true)
- .build()
+ val request = GetTopicsRequest.Builder()
+ .setAdsSdkName(mSdkName)
+ .setShouldRecordObservation(true)
+ .build()
managerCompat!!.getTopics(request)
}
// Verify that the compat code was invoked correctly.
- val captor = ArgumentCaptor.forClass(android.adservices.topics.GetTopicsRequest::class.java)
+ val captor = ArgumentCaptor
+ .forClass(android.adservices.topics.GetTopicsRequest::class.java)
verify(topicsManager).getTopics(captor.capture(), any(), any())
// Verify that the request that the compat code makes to the platform is correct.
@@ -95,26 +116,28 @@
}
@Test
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
fun testTopicsAsyncPreviewSupported() {
- val sdkExtVersion = SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
+ Assume.assumeTrue("minSdkVersion = API 33 ext 5 or API 31/32 ext 9",
+ mValidAdServicesSdkExt5Version || mValidAdExtServicesSdkExtVersion)
- Assume.assumeTrue("minSdkVersion = API 33 ext 5", sdkExtVersion >= 5)
- val topicsManager = mockTopicsManager(mContext)
+ val topicsManager = mockTopicsManager(mContext, mValidAdExtServicesSdkExtVersion)
setupTopicsResponse(topicsManager)
val managerCompat = obtain(mContext)
// Actually invoke the compat Preview API code.
val result = runBlocking {
val request =
- GetTopicsRequest.Builder().setAdsSdkName(mSdkName).setShouldRecordObservation(false)
+ GetTopicsRequest.Builder()
+ .setAdsSdkName(mSdkName)
+ .setShouldRecordObservation(false)
.build()
managerCompat!!.getTopics(request)
}
// Verify that the compat code was invoked correctly.
- val captor = ArgumentCaptor.forClass(android.adservices.topics.GetTopicsRequest::class.java)
+ val captor = ArgumentCaptor
+ .forClass(android.adservices.topics.GetTopicsRequest::class.java)
verify(topicsManager).getTopics(captor.capture(), any(), any())
// Verify that the request that the compat code makes to the platform is correct.
@@ -125,14 +148,17 @@
}
@SdkSuppress(minSdkVersion = 30)
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
companion object {
private lateinit var mContext: Context
private val mSdkName: String = "sdk1"
- private fun mockTopicsManager(spyContext: Context): TopicsManager {
+ private fun mockTopicsManager(spyContext: Context, isExtServices: Boolean): TopicsManager {
val topicsManager = mock(TopicsManager::class.java)
`when`(spyContext.getSystemService(TopicsManager::class.java)).thenReturn(topicsManager)
+ // only mock the .get() method if using extServices version
+ if (isExtServices) {
+ `when`(TopicsManager.get(any())).thenReturn(topicsManager)
+ }
return topicsManager
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManager.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManager.kt
index 17431a8..632da1b 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManager.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManager.kt
@@ -20,13 +20,8 @@
import android.annotation.SuppressLint
import android.content.Context
import android.os.LimitExceededException
-import android.os.ext.SdkExtensions
-import androidx.annotation.DoNotInline
-import androidx.annotation.RequiresExtension
import androidx.annotation.RequiresPermission
-import androidx.core.os.asOutcomeReceiver
import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
-import kotlinx.coroutines.suspendCancellableCoroutine
/**
* AdId Manager provides APIs for app and ad-SDKs to access advertising ID. The advertising ID is a
@@ -45,38 +40,6 @@
@RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_AD_ID)
abstract suspend fun getAdId(): AdId
- @SuppressLint("ClassVerificationFailure", "NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
- private class Api33Ext4Impl(
- private val mAdIdManager: android.adservices.adid.AdIdManager
- ) : AdIdManager() {
- constructor(context: Context) : this(
- context.getSystemService<android.adservices.adid.AdIdManager>(
- android.adservices.adid.AdIdManager::class.java
- )
- )
-
- @DoNotInline
- @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_AD_ID)
- override suspend fun getAdId(): AdId {
- return convertResponse(getAdIdAsyncInternal())
- }
-
- @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_AD_ID)
- private suspend fun
- getAdIdAsyncInternal(): android.adservices.adid.AdId = suspendCancellableCoroutine {
- continuation ->
- mAdIdManager.getAdId(
- Runnable::run,
- continuation.asOutcomeReceiver()
- )
- }
-
- private fun convertResponse(response: android.adservices.adid.AdId): AdId {
- return AdId(response.adId, response.isLimitAdTrackingEnabled)
- }
- }
-
companion object {
/**
* Creates [AdIdManager].
@@ -87,10 +50,11 @@
@JvmStatic
@SuppressLint("NewApi", "ClassVerificationFailure")
fun obtain(context: Context): AdIdManager? {
- return if (AdServicesInfo.version() >= 4) {
- Api33Ext4Impl(context)
+ return if (AdServicesInfo.adServicesVersion() >= 4) {
+ AdIdManagerApi33Ext4Impl(context)
+ } else if (AdServicesInfo.extServicesVersion() >= 9) {
+ AdIdManagerApi31Ext9Impl(context)
} else {
- // TODO(b/261770989): Extend this to older versions.
null
}
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerApi31Ext9Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerApi31Ext9Impl.kt
new file mode 100644
index 0000000..28d3d76
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerApi31Ext9Impl.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.adid
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+class AdIdManagerApi31Ext9Impl(context: Context) : AdIdManagerImplCommon(
+ android.adservices.adid.AdIdManager.get(context))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerApi33Ext4Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerApi33Ext4Impl.kt
new file mode 100644
index 0000000..a043fba
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerApi33Ext4Impl.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.adid
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.ext.SdkExtensions
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+class AdIdManagerApi33Ext4Impl(context: Context) : AdIdManagerImplCommon(
+ context.getSystemService(
+ android.adservices.adid.AdIdManager::class.java))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerImplCommon.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerImplCommon.kt
new file mode 100644
index 0000000..4ba59b2
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adid/AdIdManagerImplCommon.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.adid
+
+import android.adservices.common.AdServicesPermissions
+import android.annotation.SuppressLint
+import android.os.Build
+import android.os.ext.SdkExtensions
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RequiresPermission
+import androidx.annotation.RestrictTo
+import androidx.core.os.asOutcomeReceiver
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("ClassVerificationFailure", "NewApi")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+open class AdIdManagerImplCommon(
+ private val mAdIdManager: android.adservices.adid.AdIdManager
+) : AdIdManager() {
+
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_AD_ID)
+ override suspend fun getAdId(): AdId {
+ return convertResponse(getAdIdAsyncInternal())
+ }
+
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_AD_ID)
+ private suspend fun
+ getAdIdAsyncInternal(): android.adservices.adid.AdId = suspendCancellableCoroutine {
+ continuation ->
+ mAdIdManager.getAdId(
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+
+ private fun convertResponse(response: android.adservices.adid.AdId): AdId {
+ return AdId(response.adId, response.isLimitAdTrackingEnabled)
+ }
+}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManager.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManager.kt
index 7e280c4..311bc63 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManager.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManager.kt
@@ -21,16 +21,9 @@
import android.content.Context
import android.os.LimitExceededException
import android.os.TransactionTooLargeException
-import android.os.ext.SdkExtensions
-import androidx.annotation.DoNotInline
-import androidx.annotation.RequiresExtension
import androidx.annotation.RequiresPermission
-import androidx.core.os.asOutcomeReceiver
-import androidx.privacysandbox.ads.adservices.common.AdSelectionSignals
-import androidx.privacysandbox.ads.adservices.common.AdTechIdentifier
import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
import java.util.concurrent.TimeoutException
-import kotlinx.coroutines.suspendCancellableCoroutine
/**
* AdSelection Manager provides APIs for app and ad-SDKs to run ad selection processes as well
@@ -75,109 +68,6 @@
@RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
abstract suspend fun reportImpression(reportImpressionRequest: ReportImpressionRequest)
- @SuppressLint("NewApi", "ClassVerificationFailure")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
- private class Api33Ext4Impl(
- private val mAdSelectionManager: android.adservices.adselection.AdSelectionManager
- ) : AdSelectionManager() {
- constructor(context: Context) : this(
- context.getSystemService<android.adservices.adselection.AdSelectionManager>(
- android.adservices.adselection.AdSelectionManager::class.java
- )
- )
-
- @DoNotInline
- @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
- override suspend fun selectAds(adSelectionConfig: AdSelectionConfig): AdSelectionOutcome {
- return convertResponse(selectAdsInternal(convertAdSelectionConfig(adSelectionConfig)))
- }
-
- @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
- private suspend fun selectAdsInternal(
- adSelectionConfig: android.adservices.adselection.AdSelectionConfig
- ): android.adservices.adselection.AdSelectionOutcome = suspendCancellableCoroutine { cont
- ->
- mAdSelectionManager.selectAds(
- adSelectionConfig,
- Runnable::run,
- cont.asOutcomeReceiver()
- )
- }
-
- private fun convertAdSelectionConfig(
- request: AdSelectionConfig
- ): android.adservices.adselection.AdSelectionConfig {
- return android.adservices.adselection.AdSelectionConfig.Builder()
- .setAdSelectionSignals(convertAdSelectionSignals(request.adSelectionSignals))
- .setCustomAudienceBuyers(convertBuyers(request.customAudienceBuyers))
- .setDecisionLogicUri(request.decisionLogicUri)
- .setSeller(android.adservices.common.AdTechIdentifier.fromString(
- request.seller.identifier))
- .setPerBuyerSignals(convertPerBuyerSignals(request.perBuyerSignals))
- .setSellerSignals(convertAdSelectionSignals(request.sellerSignals))
- .setTrustedScoringSignalsUri(request.trustedScoringSignalsUri)
- .build()
- }
-
- private fun convertAdSelectionSignals(
- request: AdSelectionSignals
- ): android.adservices.common.AdSelectionSignals {
- return android.adservices.common.AdSelectionSignals.fromString(request.signals)
- }
-
- private fun convertBuyers(
- buyers: List<AdTechIdentifier>
- ): MutableList<android.adservices.common.AdTechIdentifier> {
- var ids = mutableListOf<android.adservices.common.AdTechIdentifier>()
- for (buyer in buyers) {
- ids.add(android.adservices.common.AdTechIdentifier.fromString(buyer.identifier))
- }
- return ids
- }
-
- private fun convertPerBuyerSignals(
- request: Map<AdTechIdentifier, AdSelectionSignals>
- ): Map<android.adservices.common.AdTechIdentifier,
- android.adservices.common.AdSelectionSignals?> {
- var map = HashMap<android.adservices.common.AdTechIdentifier,
- android.adservices.common.AdSelectionSignals?>()
- for (key in request.keys) {
- val id = android.adservices.common.AdTechIdentifier.fromString(key.identifier)
- val value = if (request[key] != null) convertAdSelectionSignals(request[key]!!)
- else null
- map[id] = value
- }
- return map
- }
-
- private fun convertResponse(
- response: android.adservices.adselection.AdSelectionOutcome
- ): AdSelectionOutcome {
- return AdSelectionOutcome(response.adSelectionId, response.renderUri)
- }
-
- @DoNotInline
- @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
- override suspend fun reportImpression(reportImpressionRequest: ReportImpressionRequest) {
- suspendCancellableCoroutine<Any> { continuation ->
- mAdSelectionManager.reportImpression(
- convertReportImpressionRequest(reportImpressionRequest),
- Runnable::run,
- continuation.asOutcomeReceiver()
- )
- }
- }
-
- private fun convertReportImpressionRequest(
- request: ReportImpressionRequest
- ): android.adservices.adselection.ReportImpressionRequest {
- return android.adservices.adselection.ReportImpressionRequest(
- request.adSelectionId,
- convertAdSelectionConfig(request.adSelectionConfig)
- )
- }
- }
-
companion object {
/**
* Creates [AdSelectionManager].
@@ -188,8 +78,10 @@
@JvmStatic
@SuppressLint("NewApi", "ClassVerificationFailure")
fun obtain(context: Context): AdSelectionManager? {
- return if (AdServicesInfo.version() >= 4) {
- Api33Ext4Impl(context)
+ return if (AdServicesInfo.adServicesVersion() >= 4) {
+ AdSelectionManagerApi33Ext4Impl(context)
+ } else if (AdServicesInfo.extServicesVersion() >= 9) {
+ AdSelectionManagerApi31Ext9Impl(context)
} else {
null
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerApi31Ext9Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerApi31Ext9Impl.kt
new file mode 100644
index 0000000..d968dd2
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerApi31Ext9Impl.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.adselection
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+class AdSelectionManagerApi31Ext9Impl(context: Context) : AdSelectionManagerImplCommon(
+ android.adservices.adselection.AdSelectionManager.get(context))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerApi33Ext4Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerApi33Ext4Impl.kt
new file mode 100644
index 0000000..b3cdd9c
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerApi33Ext4Impl.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.adselection
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.ext.SdkExtensions
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+class AdSelectionManagerApi33Ext4Impl(context: Context) : AdSelectionManagerImplCommon(
+ context.getSystemService(
+ android.adservices.adselection.AdSelectionManager::class.java))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerImplCommon.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerImplCommon.kt
new file mode 100644
index 0000000..e780975
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/adselection/AdSelectionManagerImplCommon.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.adselection
+
+import android.adservices.common.AdServicesPermissions
+import android.annotation.SuppressLint
+import android.os.Build
+import android.os.ext.SdkExtensions
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RequiresPermission
+import androidx.annotation.RestrictTo
+import androidx.core.os.asOutcomeReceiver
+import androidx.privacysandbox.ads.adservices.common.AdSelectionSignals
+import androidx.privacysandbox.ads.adservices.common.AdTechIdentifier
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+open class AdSelectionManagerImplCommon(
+ protected val mAdSelectionManager: android.adservices.adselection.AdSelectionManager
+ ) : AdSelectionManager() {
+
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
+ override suspend fun selectAds(adSelectionConfig: AdSelectionConfig): AdSelectionOutcome {
+ return convertResponse(selectAdsInternal(convertAdSelectionConfig(adSelectionConfig)))
+ }
+
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
+ private suspend fun selectAdsInternal(
+ adSelectionConfig: android.adservices.adselection.AdSelectionConfig
+ ): android.adservices.adselection.AdSelectionOutcome = suspendCancellableCoroutine { cont
+ ->
+ mAdSelectionManager.selectAds(
+ adSelectionConfig,
+ Runnable::run,
+ cont.asOutcomeReceiver()
+ )
+ }
+
+ private fun convertAdSelectionConfig(
+ request: AdSelectionConfig
+ ): android.adservices.adselection.AdSelectionConfig {
+ return android.adservices.adselection.AdSelectionConfig.Builder()
+ .setAdSelectionSignals(convertAdSelectionSignals(request.adSelectionSignals))
+ .setCustomAudienceBuyers(convertBuyers(request.customAudienceBuyers))
+ .setDecisionLogicUri(request.decisionLogicUri)
+ .setSeller(android.adservices.common.AdTechIdentifier.fromString(
+ request.seller.identifier))
+ .setPerBuyerSignals(convertPerBuyerSignals(request.perBuyerSignals))
+ .setSellerSignals(convertAdSelectionSignals(request.sellerSignals))
+ .setTrustedScoringSignalsUri(request.trustedScoringSignalsUri)
+ .build()
+ }
+
+ private fun convertAdSelectionSignals(
+ request: AdSelectionSignals
+ ): android.adservices.common.AdSelectionSignals {
+ return android.adservices.common.AdSelectionSignals.fromString(request.signals)
+ }
+
+ private fun convertBuyers(
+ buyers: List<AdTechIdentifier>
+ ): MutableList<android.adservices.common.AdTechIdentifier> {
+ val ids = mutableListOf<android.adservices.common.AdTechIdentifier>()
+ for (buyer in buyers) {
+ ids.add(android.adservices.common.AdTechIdentifier.fromString(buyer.identifier))
+ }
+ return ids
+ }
+
+ private fun convertPerBuyerSignals(
+ request: Map<AdTechIdentifier, AdSelectionSignals>
+ ): Map<android.adservices.common.AdTechIdentifier,
+ android.adservices.common.AdSelectionSignals?> {
+ val map = HashMap<android.adservices.common.AdTechIdentifier,
+ android.adservices.common.AdSelectionSignals?>()
+ for (key in request.keys) {
+ val id = android.adservices.common.AdTechIdentifier.fromString(key.identifier)
+ val value = if (request[key] != null) convertAdSelectionSignals(request[key]!!)
+ else null
+ map[id] = value
+ }
+ return map
+ }
+
+ private fun convertResponse(
+ response: android.adservices.adselection.AdSelectionOutcome
+ ): AdSelectionOutcome {
+ return AdSelectionOutcome(response.adSelectionId, response.renderUri)
+ }
+
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
+ override suspend fun reportImpression(reportImpressionRequest: ReportImpressionRequest) {
+ suspendCancellableCoroutine<Any> { continuation ->
+ mAdSelectionManager.reportImpression(
+ convertReportImpressionRequest(reportImpressionRequest),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+
+ private fun convertReportImpressionRequest(
+ request: ReportImpressionRequest
+ ): android.adservices.adselection.ReportImpressionRequest {
+ return android.adservices.adselection.ReportImpressionRequest(
+ request.adSelectionId,
+ convertAdSelectionConfig(request.adSelectionConfig)
+ )
+ }
+}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManager.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManager.kt
index d780956..88d57f1 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManager.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManager.kt
@@ -19,12 +19,7 @@
import android.annotation.SuppressLint
import android.content.Context
import android.os.LimitExceededException
-import android.os.ext.SdkExtensions
-import androidx.annotation.DoNotInline
-import androidx.annotation.RequiresExtension
-import androidx.core.os.asOutcomeReceiver
import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
-import kotlinx.coroutines.suspendCancellableCoroutine
/**
* AppSetIdManager provides APIs for app and ad-SDKs to access appSetId for non-monetizing purpose.
@@ -39,39 +34,6 @@
*/
abstract suspend fun getAppSetId(): AppSetId
- @SuppressLint("ClassVerificationFailure", "NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
- private class Api33Ext4Impl(
- private val mAppSetIdManager: android.adservices.appsetid.AppSetIdManager
- ) : AppSetIdManager() {
- constructor(context: Context) : this(
- context.getSystemService<android.adservices.appsetid.AppSetIdManager>(
- android.adservices.appsetid.AppSetIdManager::class.java
- )
- )
-
- @DoNotInline
- override suspend fun getAppSetId(): AppSetId {
- return convertResponse(getAppSetIdAsyncInternal())
- }
-
- private suspend fun getAppSetIdAsyncInternal(): android.adservices.appsetid.AppSetId =
- suspendCancellableCoroutine {
- continuation ->
- mAppSetIdManager.getAppSetId(
- Runnable::run,
- continuation.asOutcomeReceiver()
- )
- }
-
- private fun convertResponse(response: android.adservices.appsetid.AppSetId): AppSetId {
- if (response.scope == android.adservices.appsetid.AppSetId.SCOPE_APP) {
- return AppSetId(response.id, AppSetId.SCOPE_APP)
- }
- return AppSetId(response.id, AppSetId.SCOPE_DEVELOPER)
- }
- }
-
companion object {
/**
@@ -83,10 +45,11 @@
@JvmStatic
@SuppressLint("NewApi", "ClassVerificationFailure")
fun obtain(context: Context): AppSetIdManager? {
- return if (AdServicesInfo.version() >= 4) {
- Api33Ext4Impl(context)
+ return if (AdServicesInfo.adServicesVersion() >= 4) {
+ AppSetIdManagerApi33Ext4Impl(context)
+ } else if (AdServicesInfo.extServicesVersion() >= 9) {
+ AppSetIdManagerApi31Ext9Impl(context)
} else {
- // TODO(b/261770989): Extend this to older versions.
null
}
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerApi31Ext9Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerApi31Ext9Impl.kt
new file mode 100644
index 0000000..390e785
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerApi31Ext9Impl.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.appsetid
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+class AppSetIdManagerApi31Ext9Impl(context: Context) : AppSetIdManagerImplCommon(
+ android.adservices.appsetid.AppSetIdManager.get(context))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerApi33Ext4Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerApi33Ext4Impl.kt
new file mode 100644
index 0000000..84af87a
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerApi33Ext4Impl.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.appsetid
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.ext.SdkExtensions
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+class AppSetIdManagerApi33Ext4Impl(context: Context) : AppSetIdManagerImplCommon(
+ context.getSystemService(
+ android.adservices.appsetid.AppSetIdManager::class.java))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerImplCommon.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerImplCommon.kt
new file mode 100644
index 0000000..720370d
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/appsetid/AppSetIdManagerImplCommon.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.appsetid
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.os.ext.SdkExtensions
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+import androidx.core.os.asOutcomeReceiver
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("ClassVerificationFailure", "NewApi")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+open class AppSetIdManagerImplCommon(
+ private val mAppSetIdManager: android.adservices.appsetid.AppSetIdManager
+) : AppSetIdManager() {
+
+ @DoNotInline
+ override suspend fun getAppSetId(): AppSetId {
+ return convertResponse(getAppSetIdAsyncInternal())
+ }
+
+ private suspend fun getAppSetIdAsyncInternal(): android.adservices.appsetid.AppSetId =
+ suspendCancellableCoroutine {
+ continuation ->
+ mAppSetIdManager.getAppSetId(
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+
+ private fun convertResponse(response: android.adservices.appsetid.AppSetId): AppSetId {
+ if (response.scope == android.adservices.appsetid.AppSetId.SCOPE_APP) {
+ return AppSetId(response.id, AppSetId.SCOPE_APP)
+ }
+ return AppSetId(response.id, AppSetId.SCOPE_DEVELOPER)
+ }
+}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManager.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManager.kt
index 981aeaa..a9b91d7 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManager.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManager.kt
@@ -20,16 +20,8 @@
import android.annotation.SuppressLint
import android.content.Context
import android.os.LimitExceededException
-import android.os.ext.SdkExtensions
-import androidx.annotation.DoNotInline
-import androidx.annotation.RequiresExtension
import androidx.annotation.RequiresPermission
-import androidx.core.os.asOutcomeReceiver
-import androidx.privacysandbox.ads.adservices.common.AdData
-import androidx.privacysandbox.ads.adservices.common.AdSelectionSignals
-import androidx.privacysandbox.ads.adservices.common.AdTechIdentifier
import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
-import kotlinx.coroutines.suspendCancellableCoroutine
/**
* This class provides APIs for app and ad-SDKs to join / leave custom audiences.
@@ -94,111 +86,6 @@
@RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
abstract suspend fun leaveCustomAudience(request: LeaveCustomAudienceRequest)
- @SuppressLint("ClassVerificationFailure", "NewApi")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
- private class Api33Ext4Impl(
- private val customAudienceManager: android.adservices.customaudience.CustomAudienceManager
- ) : CustomAudienceManager() {
- constructor(context: Context) : this(
- context.getSystemService<android.adservices.customaudience.CustomAudienceManager>(
- android.adservices.customaudience.CustomAudienceManager::class.java
- )
- )
-
- @DoNotInline
- @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
- override suspend fun joinCustomAudience(request: JoinCustomAudienceRequest) {
- suspendCancellableCoroutine { continuation ->
- customAudienceManager.joinCustomAudience(
- convertJoinRequest(request),
- Runnable::run,
- continuation.asOutcomeReceiver()
- )
- }
- }
-
- @DoNotInline
- @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
- override suspend fun leaveCustomAudience(request: LeaveCustomAudienceRequest) {
- suspendCancellableCoroutine { continuation ->
- customAudienceManager.leaveCustomAudience(
- convertLeaveRequest(request),
- Runnable::run,
- continuation.asOutcomeReceiver()
- )
- }
- }
-
- private fun convertJoinRequest(
- request: JoinCustomAudienceRequest
- ): android.adservices.customaudience.JoinCustomAudienceRequest {
- return android.adservices.customaudience.JoinCustomAudienceRequest.Builder()
- .setCustomAudience(convertCustomAudience(request.customAudience))
- .build()
- }
-
- private fun convertLeaveRequest(
- request: LeaveCustomAudienceRequest
- ): android.adservices.customaudience.LeaveCustomAudienceRequest {
- return android.adservices.customaudience.LeaveCustomAudienceRequest.Builder()
- .setBuyer(convertAdTechIdentifier(request.buyer))
- .setName(request.name)
- .build()
- }
-
- private fun convertCustomAudience(
- request: CustomAudience
- ): android.adservices.customaudience.CustomAudience {
- return android.adservices.customaudience.CustomAudience.Builder()
- .setActivationTime(request.activationTime)
- .setAds(convertAdData(request.ads))
- .setBiddingLogicUri(request.biddingLogicUri)
- .setBuyer(convertAdTechIdentifier(request.buyer))
- .setDailyUpdateUri(request.dailyUpdateUri)
- .setExpirationTime(request.expirationTime)
- .setName(request.name)
- .setTrustedBiddingData(convertTrustedSignals(request.trustedBiddingSignals))
- .setUserBiddingSignals(convertBiddingSignals(request.userBiddingSignals))
- .build()
- }
-
- private fun convertAdData(
- input: List<AdData>
- ): List<android.adservices.common.AdData> {
- val result = mutableListOf<android.adservices.common.AdData>()
- for (ad in input) {
- result.add(android.adservices.common.AdData.Builder()
- .setMetadata(ad.metadata)
- .setRenderUri(ad.renderUri)
- .build())
- }
- return result
- }
-
- private fun convertAdTechIdentifier(
- input: AdTechIdentifier
- ): android.adservices.common.AdTechIdentifier {
- return android.adservices.common.AdTechIdentifier.fromString(input.identifier)
- }
-
- private fun convertTrustedSignals(
- input: TrustedBiddingData?
- ): android.adservices.customaudience.TrustedBiddingData? {
- if (input == null) return null
- return android.adservices.customaudience.TrustedBiddingData.Builder()
- .setTrustedBiddingKeys(input.trustedBiddingKeys)
- .setTrustedBiddingUri(input.trustedBiddingUri)
- .build()
- }
-
- private fun convertBiddingSignals(
- input: AdSelectionSignals?
- ): android.adservices.common.AdSelectionSignals? {
- if (input == null) return null
- return android.adservices.common.AdSelectionSignals.fromString(input.signals)
- }
- }
-
companion object {
/**
* Creates [CustomAudienceManager].
@@ -209,8 +96,10 @@
@JvmStatic
@SuppressLint("NewApi", "ClassVerificationFailure")
fun obtain(context: Context): CustomAudienceManager? {
- return if (AdServicesInfo.version() >= 4) {
- Api33Ext4Impl(context)
+ return if (AdServicesInfo.adServicesVersion() >= 4) {
+ CustomAudienceManagerApi33Ext4Impl(context)
+ } else if (AdServicesInfo.extServicesVersion() >= 9) {
+ CustomAudienceManagerApi31Ext9Impl(context)
} else {
null
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerApi31Ext9Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerApi31Ext9Impl.kt
new file mode 100644
index 0000000..1e294ce
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerApi31Ext9Impl.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.customaudience
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+class CustomAudienceManagerApi31Ext9Impl(context: Context) : CustomAudienceManagerImplCommon(
+ android.adservices.customaudience.CustomAudienceManager.get(context))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerApi33Ext4Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerApi33Ext4Impl.kt
new file mode 100644
index 0000000..fd658d7
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerApi33Ext4Impl.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.customaudience
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.ext.SdkExtensions
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+class CustomAudienceManagerApi33Ext4Impl(context: Context) : CustomAudienceManagerImplCommon(
+ context.getSystemService(android.adservices.customaudience.CustomAudienceManager::class.java))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerImplCommon.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerImplCommon.kt
new file mode 100644
index 0000000..44f09a8
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/CustomAudienceManagerImplCommon.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.customaudience
+
+import android.adservices.common.AdServicesPermissions
+import android.annotation.SuppressLint
+import android.os.Build
+import android.os.ext.SdkExtensions
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RequiresPermission
+import androidx.annotation.RestrictTo
+import androidx.core.os.asOutcomeReceiver
+import androidx.privacysandbox.ads.adservices.common.AdData
+import androidx.privacysandbox.ads.adservices.common.AdSelectionSignals
+import androidx.privacysandbox.ads.adservices.common.AdTechIdentifier
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+open class CustomAudienceManagerImplCommon(
+ protected val customAudienceManager: android.adservices.customaudience.CustomAudienceManager
+ ) : CustomAudienceManager() {
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
+ override suspend fun joinCustomAudience(request: JoinCustomAudienceRequest) {
+ suspendCancellableCoroutine { continuation ->
+ customAudienceManager.joinCustomAudience(
+ convertJoinRequest(request),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_CUSTOM_AUDIENCE)
+ override suspend fun leaveCustomAudience(request: LeaveCustomAudienceRequest) {
+ suspendCancellableCoroutine { continuation ->
+ customAudienceManager.leaveCustomAudience(
+ convertLeaveRequest(request),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+
+ private fun convertJoinRequest(
+ request: JoinCustomAudienceRequest
+ ): android.adservices.customaudience.JoinCustomAudienceRequest {
+ return android.adservices.customaudience.JoinCustomAudienceRequest.Builder()
+ .setCustomAudience(convertCustomAudience(request.customAudience))
+ .build()
+ }
+
+ private fun convertLeaveRequest(
+ request: LeaveCustomAudienceRequest
+ ): android.adservices.customaudience.LeaveCustomAudienceRequest {
+ return android.adservices.customaudience.LeaveCustomAudienceRequest.Builder()
+ .setBuyer(convertAdTechIdentifier(request.buyer))
+ .setName(request.name)
+ .build()
+ }
+
+ private fun convertCustomAudience(
+ request: CustomAudience
+ ): android.adservices.customaudience.CustomAudience {
+ return android.adservices.customaudience.CustomAudience.Builder()
+ .setActivationTime(request.activationTime)
+ .setAds(convertAdData(request.ads))
+ .setBiddingLogicUri(request.biddingLogicUri)
+ .setBuyer(convertAdTechIdentifier(request.buyer))
+ .setDailyUpdateUri(request.dailyUpdateUri)
+ .setExpirationTime(request.expirationTime)
+ .setName(request.name)
+ .setTrustedBiddingData(convertTrustedSignals(request.trustedBiddingSignals))
+ .setUserBiddingSignals(convertBiddingSignals(request.userBiddingSignals))
+ .build()
+ }
+
+ private fun convertAdData(
+ input: List<AdData>
+ ): List<android.adservices.common.AdData> {
+ val result = mutableListOf<android.adservices.common.AdData>()
+ for (ad in input) {
+ result.add(android.adservices.common.AdData.Builder()
+ .setMetadata(ad.metadata)
+ .setRenderUri(ad.renderUri)
+ .build())
+ }
+ return result
+ }
+
+ private fun convertAdTechIdentifier(
+ input: AdTechIdentifier
+ ): android.adservices.common.AdTechIdentifier {
+ return android.adservices.common.AdTechIdentifier.fromString(input.identifier)
+ }
+
+ private fun convertTrustedSignals(
+ input: TrustedBiddingData?
+ ): android.adservices.customaudience.TrustedBiddingData? {
+ if (input == null) return null
+ return android.adservices.customaudience.TrustedBiddingData.Builder()
+ .setTrustedBiddingKeys(input.trustedBiddingKeys)
+ .setTrustedBiddingUri(input.trustedBiddingUri)
+ .build()
+ }
+
+ private fun convertBiddingSignals(
+ input: AdSelectionSignals?
+ ): android.adservices.common.AdSelectionSignals? {
+ if (input == null) return null
+ return android.adservices.common.AdSelectionSignals.fromString(input.signals)
+ }
+}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/internal/AdServicesInfo.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/internal/AdServicesInfo.kt
index 9b36692..6f8b056 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/internal/AdServicesInfo.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/internal/AdServicesInfo.kt
@@ -21,24 +21,38 @@
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
-/**
- * Temporary replacement for BuildCompat.AD_SERVICES_EXTENSION_INT.
- * TODO(b/261755947) Replace with AD_SERVICES_EXTENSION_INT after new core library release
- */
internal object AdServicesInfo {
- fun version(): Int {
- return if (Build.VERSION.SDK_INT >= 30) {
+ fun adServicesVersion(): Int {
+ return if (Build.VERSION.SDK_INT >= 33) {
Extensions30Impl.getAdServicesVersion()
} else {
0
}
}
+ fun extServicesVersion(): Int {
+ return if (Build.VERSION.SDK_INT == 31 || Build.VERSION.SDK_INT == 32) {
+ Extensions30ExtImpl.getAdExtServicesVersion()
+ } else {
+ 0
+ }
+ }
+
@RequiresApi(30)
private object Extensions30Impl {
@DoNotInline
fun getAdServicesVersion() =
SdkExtensions.getExtensionVersion(SdkExtensions.AD_SERVICES)
}
+
+ @RequiresApi(30)
+ private object Extensions30ExtImpl {
+ // For ExtServices, there is no AD_SERVICES extension version, so we need to check
+ // for the build version. Use S for now, but this can be changed to R when we add
+ // support for R later.
+ @DoNotInline
+ fun getAdExtServicesVersion() =
+ SdkExtensions.getExtensionVersion(Build.VERSION_CODES.S)
+ }
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManager.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManager.kt
index de62bd2..4641d2b 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManager.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManager.kt
@@ -20,18 +20,11 @@
import android.annotation.SuppressLint
import android.content.Context
import android.net.Uri
-import android.os.ext.SdkExtensions
import android.util.Log
import android.view.InputEvent
-import androidx.annotation.DoNotInline
-import androidx.annotation.RequiresExtension
import androidx.annotation.RequiresPermission
-import androidx.core.os.asOutcomeReceiver
import androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures
import androidx.privacysandbox.ads.adservices.internal.AdServicesInfo
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.suspendCancellableCoroutine
/**
* This class provides APIs to manage ads attribution using Privacy Sandbox.
@@ -103,167 +96,6 @@
@RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION)
abstract suspend fun getMeasurementApiStatus(): Int
- @SuppressLint("NewApi", "ClassVerificationFailure")
- @RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
- private class Api33Ext5Impl(
- private val mMeasurementManager: android.adservices.measurement.MeasurementManager
- ) : MeasurementManager() {
- constructor(context: Context) : this(
- context.getSystemService<android.adservices.measurement.MeasurementManager>(
- android.adservices.measurement.MeasurementManager::class.java
- )
- )
-
- @DoNotInline
- override suspend fun deleteRegistrations(deletionRequest: DeletionRequest) {
- suspendCancellableCoroutine<Any> { continuation ->
- mMeasurementManager.deleteRegistrations(
- convertDeletionRequest(deletionRequest),
- Runnable::run,
- continuation.asOutcomeReceiver()
- )
- }
- }
-
- private fun convertDeletionRequest(
- request: DeletionRequest
- ): android.adservices.measurement.DeletionRequest {
- return android.adservices.measurement.DeletionRequest.Builder()
- .setDeletionMode(request.deletionMode)
- .setMatchBehavior(request.matchBehavior)
- .setStart(request.start)
- .setEnd(request.end)
- .setDomainUris(request.domainUris)
- .setOriginUris(request.originUris)
- .build()
- }
-
- @DoNotInline
- @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION)
- override suspend fun registerSource(attributionSource: Uri, inputEvent: InputEvent?) {
- suspendCancellableCoroutine<Any> { continuation ->
- mMeasurementManager.registerSource(
- attributionSource,
- inputEvent,
- Runnable::run,
- continuation.asOutcomeReceiver()
- )
- }
- }
-
- @DoNotInline
- @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION)
- override suspend fun registerTrigger(trigger: Uri) {
- suspendCancellableCoroutine<Any> { continuation ->
- mMeasurementManager.registerTrigger(
- trigger,
- Runnable::run,
- continuation.asOutcomeReceiver())
- }
- }
-
- @DoNotInline
- @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION)
- override suspend fun registerWebSource(request: WebSourceRegistrationRequest) {
- suspendCancellableCoroutine<Any> { continuation ->
- mMeasurementManager.registerWebSource(
- convertWebSourceRequest(request),
- Runnable::run,
- continuation.asOutcomeReceiver())
- }
- }
-
- @DoNotInline
- @ExperimentalFeatures.RegisterSourceOptIn
- @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION)
- override suspend fun registerSource(
- request: SourceRegistrationRequest
- ): Unit = coroutineScope {
- request.registrationUris.forEach { uri ->
- launch {
- suspendCancellableCoroutine<Any> { continuation ->
- mMeasurementManager.registerSource(
- uri,
- request.inputEvent,
- Runnable::run,
- continuation.asOutcomeReceiver()
- )
- }
- }
- }
- }
-
- private fun convertWebSourceRequest(
- request: WebSourceRegistrationRequest
- ): android.adservices.measurement.WebSourceRegistrationRequest {
- return android.adservices.measurement.WebSourceRegistrationRequest
- .Builder(
- convertWebSourceParams(request.webSourceParams),
- request.topOriginUri)
- .setWebDestination(request.webDestination)
- .setAppDestination(request.appDestination)
- .setInputEvent(request.inputEvent)
- .setVerifiedDestination(request.verifiedDestination)
- .build()
- }
-
- private fun convertWebSourceParams(
- request: List<WebSourceParams>
- ): List<android.adservices.measurement.WebSourceParams> {
- var result = mutableListOf<android.adservices.measurement.WebSourceParams>()
- for (param in request) {
- result.add(android.adservices.measurement.WebSourceParams
- .Builder(param.registrationUri)
- .setDebugKeyAllowed(param.debugKeyAllowed)
- .build())
- }
- return result
- }
-
- @DoNotInline
- @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION)
- override suspend fun registerWebTrigger(request: WebTriggerRegistrationRequest) {
- suspendCancellableCoroutine<Any> { continuation ->
- mMeasurementManager.registerWebTrigger(
- convertWebTriggerRequest(request),
- Runnable::run,
- continuation.asOutcomeReceiver())
- }
- }
-
- private fun convertWebTriggerRequest(
- request: WebTriggerRegistrationRequest
- ): android.adservices.measurement.WebTriggerRegistrationRequest {
- return android.adservices.measurement.WebTriggerRegistrationRequest
- .Builder(
- convertWebTriggerParams(request.webTriggerParams),
- request.destination)
- .build()
- }
-
- private fun convertWebTriggerParams(
- request: List<WebTriggerParams>
- ): List<android.adservices.measurement.WebTriggerParams> {
- var result = mutableListOf<android.adservices.measurement.WebTriggerParams>()
- for (param in request) {
- result.add(android.adservices.measurement.WebTriggerParams
- .Builder(param.registrationUri)
- .setDebugKeyAllowed(param.debugKeyAllowed)
- .build())
- }
- return result
- }
-
- @DoNotInline
- @RequiresPermission(ACCESS_ADSERVICES_ATTRIBUTION)
- override suspend fun getMeasurementApiStatus(): Int = suspendCancellableCoroutine {
- continuation ->
- mMeasurementManager.getMeasurementApiStatus(
- Runnable::run,
- continuation.asOutcomeReceiver())
- }
- }
-
companion object {
/**
* This state indicates that Measurement APIs are unavailable. Invoking them will result
@@ -284,9 +116,12 @@
@JvmStatic
@SuppressLint("NewApi", "ClassVerificationFailure")
fun obtain(context: Context): MeasurementManager? {
- Log.d("MeasurementManager", "AdServicesInfo.version=${AdServicesInfo.version()}")
- return if (AdServicesInfo.version() >= 5) {
- Api33Ext5Impl(context)
+ Log.d("MeasurementManager",
+ "AdServicesInfo.version=${AdServicesInfo.adServicesVersion()}")
+ return if (AdServicesInfo.adServicesVersion() >= 5) {
+ MeasurementManagerApi33Ext5Impl(context)
+ } else if (AdServicesInfo.extServicesVersion() >= 9) {
+ MeasurementManagerApi31Ext9Impl(context)
} else {
null
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerApi31Ext9Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerApi31Ext9Impl.kt
new file mode 100644
index 0000000..4d55606
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerApi31Ext9Impl.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.measurement
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+class MeasurementManagerApi31Ext9Impl(context: Context) : MeasurementManagerImplCommon(
+ android.adservices.measurement.MeasurementManager.get(context))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerApi33Ext5Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerApi33Ext5Impl.kt
new file mode 100644
index 0000000..cf0de76
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerApi33Ext5Impl.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.measurement
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.ext.SdkExtensions
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
+class MeasurementManagerApi33Ext5Impl(context: Context) : MeasurementManagerImplCommon(
+ context.getSystemService(android.adservices.measurement.MeasurementManager::class.java))
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerImplCommon.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerImplCommon.kt
new file mode 100644
index 0000000..3618240
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/measurement/MeasurementManagerImplCommon.kt
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.measurement
+
+import android.adservices.common.AdServicesPermissions
+import android.annotation.SuppressLint
+import android.net.Uri
+import android.os.Build
+import android.os.ext.SdkExtensions
+import android.view.InputEvent
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RequiresPermission
+import androidx.annotation.RestrictTo
+import androidx.core.os.asOutcomeReceiver
+import androidx.privacysandbox.ads.adservices.common.ExperimentalFeatures
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 5)
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+open class MeasurementManagerImplCommon(
+ protected val mMeasurementManager: android.adservices.measurement.MeasurementManager
+ ) : MeasurementManager() {
+ @DoNotInline
+ override suspend fun deleteRegistrations(deletionRequest: DeletionRequest) {
+ suspendCancellableCoroutine<Any> { continuation ->
+ mMeasurementManager.deleteRegistrations(
+ convertDeletionRequest(deletionRequest),
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+
+ private fun convertDeletionRequest(
+ request: DeletionRequest
+ ): android.adservices.measurement.DeletionRequest {
+ return android.adservices.measurement.DeletionRequest.Builder()
+ .setDeletionMode(request.deletionMode)
+ .setMatchBehavior(request.matchBehavior)
+ .setStart(request.start)
+ .setEnd(request.end)
+ .setDomainUris(request.domainUris)
+ .setOriginUris(request.originUris)
+ .build()
+ }
+
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
+ override suspend fun registerSource(attributionSource: Uri, inputEvent: InputEvent?) {
+ suspendCancellableCoroutine<Any> { continuation ->
+ mMeasurementManager.registerSource(
+ attributionSource,
+ inputEvent,
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
+ override suspend fun registerTrigger(trigger: Uri) {
+ suspendCancellableCoroutine<Any> { continuation ->
+ mMeasurementManager.registerTrigger(
+ trigger,
+ Runnable::run,
+ continuation.asOutcomeReceiver())
+ }
+ }
+
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
+ override suspend fun registerWebSource(request: WebSourceRegistrationRequest) {
+ suspendCancellableCoroutine<Any> { continuation ->
+ mMeasurementManager.registerWebSource(
+ convertWebSourceRequest(request),
+ Runnable::run,
+ continuation.asOutcomeReceiver())
+ }
+ }
+
+ @DoNotInline
+ @ExperimentalFeatures.RegisterSourceOptIn
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
+ override suspend fun registerSource(
+ request: SourceRegistrationRequest
+ ): Unit = coroutineScope {
+ request.registrationUris.forEach { uri ->
+ launch {
+ suspendCancellableCoroutine<Any> { continuation ->
+ mMeasurementManager.registerSource(
+ uri,
+ request.inputEvent,
+ Runnable::run,
+ continuation.asOutcomeReceiver()
+ )
+ }
+ }
+ }
+ }
+
+ private fun convertWebSourceRequest(
+ request: WebSourceRegistrationRequest
+ ): android.adservices.measurement.WebSourceRegistrationRequest {
+ return android.adservices.measurement.WebSourceRegistrationRequest
+ .Builder(
+ convertWebSourceParams(request.webSourceParams),
+ request.topOriginUri)
+ .setWebDestination(request.webDestination)
+ .setAppDestination(request.appDestination)
+ .setInputEvent(request.inputEvent)
+ .setVerifiedDestination(request.verifiedDestination)
+ .build()
+ }
+
+ private fun convertWebSourceParams(
+ request: List<WebSourceParams>
+ ): List<android.adservices.measurement.WebSourceParams> {
+ var result = mutableListOf<android.adservices.measurement.WebSourceParams>()
+ for (param in request) {
+ result.add(android.adservices.measurement.WebSourceParams
+ .Builder(param.registrationUri)
+ .setDebugKeyAllowed(param.debugKeyAllowed)
+ .build())
+ }
+ return result
+ }
+
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
+ override suspend fun registerWebTrigger(request: WebTriggerRegistrationRequest) {
+ suspendCancellableCoroutine<Any> { continuation ->
+ mMeasurementManager.registerWebTrigger(
+ convertWebTriggerRequest(request),
+ Runnable::run,
+ continuation.asOutcomeReceiver())
+ }
+ }
+
+ private fun convertWebTriggerRequest(
+ request: WebTriggerRegistrationRequest
+ ): android.adservices.measurement.WebTriggerRegistrationRequest {
+ return android.adservices.measurement.WebTriggerRegistrationRequest
+ .Builder(
+ convertWebTriggerParams(request.webTriggerParams),
+ request.destination)
+ .build()
+ }
+
+ private fun convertWebTriggerParams(
+ request: List<WebTriggerParams>
+ ): List<android.adservices.measurement.WebTriggerParams> {
+ var result = mutableListOf<android.adservices.measurement.WebTriggerParams>()
+ for (param in request) {
+ result.add(android.adservices.measurement.WebTriggerParams
+ .Builder(param.registrationUri)
+ .setDebugKeyAllowed(param.debugKeyAllowed)
+ .build())
+ }
+ return result
+ }
+
+ @DoNotInline
+ @RequiresPermission(AdServicesPermissions.ACCESS_ADSERVICES_ATTRIBUTION)
+ override suspend fun getMeasurementApiStatus(): Int = suspendCancellableCoroutine {
+ continuation ->
+ mMeasurementManager.getMeasurementApiStatus(
+ Runnable::run,
+ continuation.asOutcomeReceiver())
+ }
+}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManager.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManager.kt
index 828fdf9..ab533f0 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManager.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManager.kt
@@ -50,10 +50,12 @@
@JvmStatic
@SuppressLint("NewApi", "ClassVerificationFailure")
fun obtain(context: Context): TopicsManager? {
- return if (AdServicesInfo.version() >= 5) {
+ return if (AdServicesInfo.adServicesVersion() >= 5) {
TopicsManagerApi33Ext5Impl(context)
- } else if (AdServicesInfo.version() == 4) {
+ } else if (AdServicesInfo.adServicesVersion() == 4) {
TopicsManagerApi33Ext4Impl(context)
+ } else if (AdServicesInfo.extServicesVersion() >= 9) {
+ TopicsManagerApi31Ext9Impl(context)
} else {
null
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerApi31Ext9Impl.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerApi31Ext9Impl.kt
new file mode 100644
index 0000000..c9aedf9
--- /dev/null
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerApi31Ext9Impl.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.ads.adservices.topics
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.os.Build
+import androidx.annotation.RequiresExtension
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@SuppressLint("NewApi", "ClassVerificationFailure")
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
+class TopicsManagerApi31Ext9Impl(context: Context) : TopicsManagerImplCommon(
+ android.adservices.topics.TopicsManager.get(context)) {
+
+ override fun convertRequest(
+ request: GetTopicsRequest
+ ): android.adservices.topics.GetTopicsRequest {
+ return android.adservices.topics.GetTopicsRequest.Builder()
+ .setAdsSdkName(request.adsSdkName)
+ .setShouldRecordObservation(request.shouldRecordObservation)
+ .build()
+ }
+}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerImplCommon.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerImplCommon.kt
index 7dc5752..2b09952 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerImplCommon.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/topics/TopicsManagerImplCommon.kt
@@ -1,7 +1,24 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package androidx.privacysandbox.ads.adservices.topics
import android.adservices.common.AdServicesPermissions
import android.annotation.SuppressLint
+import android.os.Build
import android.os.ext.SdkExtensions
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresExtension
@@ -13,6 +30,7 @@
@RestrictTo(RestrictTo.Scope.LIBRARY)
@SuppressLint("NewApi")
@RequiresExtension(extension = SdkExtensions.AD_SERVICES, version = 4)
+@RequiresExtension(extension = Build.VERSION_CODES.S, version = 9)
open class TopicsManagerImplCommon(
private val mTopicsManager: android.adservices.topics.TopicsManager
) : TopicsManager() {