Introduce dedicated Privacy Sandbox Activity libraries.
This deprecates the SdkActivityLauncher interface and utilities from the
UI library and moves it to dedicates libraries under
androidx.privacysandbox.activity.{core,client,provider}.
There is no extra functionality added, this is a simple refactor with
the following (minor) differences:
- The client test now shares the same package as the library.
- The libraries now depend on the published version of androidx.core.
- We now use Stable AIDL to define the AIDL interfaces.
Bug: 307515108
Relnote: "Introduce dedicated Privacy Sandbox Activity library. It
contains interfaces for launching activities from the SDK Runtime. The
interfaces were previously defined in the Privacy Sandbox UI library."
Test: ./gradlew
privacysandbox:activity:activity-{client,provider}:connectedAndroidTests
privacysandbox:ui:ui-{client,provider}:connectedAndroidTests
Change-Id: I68beb04e2ec882bbf13b87d5b29e5885bc74ddce
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 5040829..805070a 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -292,6 +292,9 @@
docs(project(":preference:preference"))
docs(project(":preference:preference-ktx"))
docs(project(":print:print"))
+ docs(project(":privacysandbox:activity:activity-client"))
+ docs(project(":privacysandbox:activity:activity-core"))
+ docs(project(":privacysandbox:activity:activity-provider"))
docs(project(":privacysandbox:ads:ads-adservices"))
docs(project(":privacysandbox:ads:ads-adservices-java"))
docs(project(":privacysandbox:sdkruntime:sdkruntime-client"))
diff --git a/libraryversions.toml b/libraryversions.toml
index 6a80758..8218f60 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -102,6 +102,7 @@
PERCENTLAYOUT = "1.1.0-alpha01"
PREFERENCE = "1.3.0-alpha01"
PRINT = "1.1.0-beta01"
+PRIVACYSANDBOX_ACTIVITY = "1.0.0-alpha01"
PRIVACYSANDBOX_ADS = "1.1.0-beta02"
PRIVACYSANDBOX_PLUGINS = "1.0.0-alpha03"
PRIVACYSANDBOX_SDKRUNTIME = "1.0.0-alpha10"
@@ -165,7 +166,6 @@
WINDOW_EXTENSIONS = "1.2.0-rc01"
WINDOW_EXTENSIONS_CORE = "1.1.0-alpha01"
WINDOW_SIDECAR = "1.0.0-rc01"
-# Do not remove comment
WORK = "2.10.0-alpha01"
[groups]
@@ -246,6 +246,7 @@
PERCENTLAYOUT = { group = "androidx.percentlayout", atomicGroupVersion = "versions.PERCENTLAYOUT" }
PREFERENCE = { group = "androidx.preference", atomicGroupVersion = "versions.PREFERENCE" }
PRINT = { group = "androidx.print", atomicGroupVersion = "versions.PRINT" }
+PRIVACYSANDBOX_ACTIVITY = { group = "androidx.privacysandbox.activity", atomicGroupVersion = "versions.PRIVACYSANDBOX_ACTIVITY" }
PRIVACYSANDBOX_ADS = { group = "androidx.privacysandbox.ads", atomicGroupVersion = "versions.PRIVACYSANDBOX_ADS" }
PRIVACYSANDBOX_PLUGINS = { group = "androidx.privacysandbox.plugins", atomicGroupVersion = "versions.PRIVACYSANDBOX_PLUGINS" }
PRIVACYSANDBOX_SDKRUNTIME = { group = "androidx.privacysandbox.sdkruntime", atomicGroupVersion = "versions.PRIVACYSANDBOX_SDKRUNTIME" }
diff --git a/privacysandbox/activity/activity-client/api/current.txt b/privacysandbox/activity/activity-client/api/current.txt
new file mode 100644
index 0000000..b744203
--- /dev/null
+++ b/privacysandbox/activity/activity-client/api/current.txt
@@ -0,0 +1,14 @@
+// Signature format: 4.0
+package androidx.privacysandbox.activity.client {
+
+ public interface LocalSdkActivityLauncher<T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> extends androidx.privacysandbox.activity.core.SdkActivityLauncher {
+ method public void dispose();
+ }
+
+ public final class SdkActivityLaunchers {
+ method public static <T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> androidx.privacysandbox.activity.client.LocalSdkActivityLauncher<T> createSdkActivityLauncher(T, kotlin.jvm.functions.Function0<java.lang.Boolean> allowLaunch);
+ method public static android.os.Bundle toLauncherInfo(androidx.privacysandbox.activity.core.SdkActivityLauncher);
+ }
+
+}
+
diff --git a/privacysandbox/activity/activity-client/api/res-current.txt b/privacysandbox/activity/activity-client/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/privacysandbox/activity/activity-client/api/res-current.txt
diff --git a/privacysandbox/activity/activity-client/api/restricted_current.txt b/privacysandbox/activity/activity-client/api/restricted_current.txt
new file mode 100644
index 0000000..b744203
--- /dev/null
+++ b/privacysandbox/activity/activity-client/api/restricted_current.txt
@@ -0,0 +1,14 @@
+// Signature format: 4.0
+package androidx.privacysandbox.activity.client {
+
+ public interface LocalSdkActivityLauncher<T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> extends androidx.privacysandbox.activity.core.SdkActivityLauncher {
+ method public void dispose();
+ }
+
+ public final class SdkActivityLaunchers {
+ method public static <T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> androidx.privacysandbox.activity.client.LocalSdkActivityLauncher<T> createSdkActivityLauncher(T, kotlin.jvm.functions.Function0<java.lang.Boolean> allowLaunch);
+ method public static android.os.Bundle toLauncherInfo(androidx.privacysandbox.activity.core.SdkActivityLauncher);
+ }
+
+}
+
diff --git a/privacysandbox/activity/activity-client/build.gradle b/privacysandbox/activity/activity-client/build.gradle
new file mode 100644
index 0000000..f7ec166
--- /dev/null
+++ b/privacysandbox/activity/activity-client/build.gradle
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 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.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+ api("androidx.annotation:annotation:1.1.0")
+
+ implementation("androidx.core:core:1.12.0")
+ implementation("androidx.lifecycle:lifecycle-common:2.2.0")
+ implementation("androidx.privacysandbox.sdkruntime:sdkruntime-client:1.0.0-alpha08")
+ implementation(project(":privacysandbox:activity:activity-core"))
+
+ androidTestImplementation(project(":internal-testutils-runtime"))
+ androidTestImplementation(project(":appcompat:appcompat"))
+ androidTestImplementation(libs.espressoIntents)
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.truth)
+}
+
+android {
+ namespace "androidx.privacysandbox.activity.client"
+ defaultConfig {
+ minSdk 21
+ }
+}
+
+androidx {
+ name = "androidx.privacysandbox.activity:activity-client"
+ type = LibraryType.PUBLISHED_LIBRARY
+ inceptionYear = "2023"
+ description = "Manage Privacy Sandbox Activities from outside the sandbox."
+}
diff --git a/privacysandbox/activity/activity-client/src/androidTest/AndroidManifest.xml b/privacysandbox/activity/activity-client/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..7cbcd44
--- /dev/null
+++ b/privacysandbox/activity/activity-client/src/androidTest/AndroidManifest.xml
@@ -0,0 +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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+ <application>
+ <activity
+ android:name="androidx.privacysandbox.activity.client.TestActivity"
+ android:theme="@style/Theme.AppCompat"
+ android:exported="true"/>
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/privacysandbox/activity/activity-client/src/androidTest/java/androidx/privacysandbox/activity/client/CreateSdkActivityLauncherTest.kt b/privacysandbox/activity/activity-client/src/androidTest/java/androidx/privacysandbox/activity/client/CreateSdkActivityLauncherTest.kt
new file mode 100644
index 0000000..969a525
--- /dev/null
+++ b/privacysandbox/activity/activity-client/src/androidTest/java/androidx/privacysandbox/activity/client/CreateSdkActivityLauncherTest.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.activity.client
+
+import android.app.Activity
+import android.app.Instrumentation.ActivityResult
+import android.content.Intent
+import android.os.Binder
+import android.os.Build
+import androidx.lifecycle.Lifecycle
+import androidx.test.espresso.intent.Intents.intended
+import androidx.test.espresso.intent.Intents.intending
+import androidx.test.espresso.intent.Intents.times
+import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
+import androidx.test.espresso.intent.rule.IntentsRule
+import androidx.test.ext.junit.rules.ActivityScenarioRule
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import androidx.testutils.withActivity
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import org.hamcrest.Matchers.`is`
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
+class CreateSdkActivityLauncherTest {
+ @get:Rule
+ var activityScenarioRule = ActivityScenarioRule(TestActivity::class.java)
+
+ @get:Rule
+ var intentsRule = IntentsRule()
+
+ private val sdkSandboxActivityMatcher =
+ hasAction(`is`("android.app.sdksandbox.action.START_SANDBOXED_ACTIVITY"))
+
+ @Before
+ fun setUp() {
+ // Intercepts intent to start sandboxed activity and immediately return a result.
+ // This allows us to avoid loading and setting up an SDK just for checking if activities are
+ // launched.
+ intending(sdkSandboxActivityMatcher)
+ .respondWith(ActivityResult(Activity.RESULT_OK, Intent()))
+ }
+
+ @Test
+ fun returnedLauncher_launchesActivitiesWhenAllowed() = runBlocking {
+ val launcher = activityScenarioRule.withActivity { this.createSdkActivityLauncher { true } }
+
+ val result = launcher.launchSdkActivity(Binder())
+
+ assertThat(result).isTrue()
+ intended(sdkSandboxActivityMatcher, times(1))
+ }
+
+ @Test
+ fun returnedLauncher_rejectsActivityLaunchesAccordingToPredicate() = runBlocking {
+ val launcher =
+ activityScenarioRule.withActivity { this.createSdkActivityLauncher { false } }
+
+ val result = launcher.launchSdkActivity(Binder())
+
+ assertThat(result).isFalse()
+ intended(sdkSandboxActivityMatcher, times(0))
+ }
+
+ @Test
+ fun returnedLauncher_rejectsActivityLaunchesWhenDisposed() = runBlocking {
+ val launcher = activityScenarioRule.withActivity { this.createSdkActivityLauncher { true } }
+ launcher.dispose()
+
+ val result = launcher.launchSdkActivity(Binder())
+
+ assertThat(result).isFalse()
+ intended(sdkSandboxActivityMatcher, times(0))
+ }
+
+ @Test
+ fun returnedLauncher_disposeCanBeCalledMultipleTimes() = runBlocking {
+ val launcher = activityScenarioRule.withActivity { this.createSdkActivityLauncher { true } }
+ launcher.dispose()
+
+ val result = launcher.launchSdkActivity(Binder())
+ launcher.dispose()
+ launcher.dispose()
+
+ assertThat(result).isFalse()
+ intended(sdkSandboxActivityMatcher, times(0))
+ }
+
+ @Test
+ fun returnedLauncher_rejectsActivityLaunchesWhenHostActivityIsDestroyed() = runBlocking {
+ val launcher = activityScenarioRule.withActivity { this.createSdkActivityLauncher { true } }
+ activityScenarioRule.scenario.moveToState(Lifecycle.State.DESTROYED)
+
+ val result = launcher.launchSdkActivity(Binder())
+
+ assertThat(result).isFalse()
+ intended(sdkSandboxActivityMatcher, times(0))
+ }
+
+ @Test
+ fun returnedLauncher_rejectsActivityLaunchesWhenHostActivityWasAlreadyDestroyed() =
+ runBlocking {
+ val activity = activityScenarioRule.withActivity { this }
+ activityScenarioRule.scenario.moveToState(Lifecycle.State.DESTROYED)
+ val launcher = activity.createSdkActivityLauncher { true }
+
+ val result = launcher.launchSdkActivity(Binder())
+
+ assertThat(result).isFalse()
+ intended(sdkSandboxActivityMatcher, times(0))
+ }
+}
diff --git a/privacysandbox/activity/activity-client/src/androidTest/java/androidx/privacysandbox/activity/client/TestActivity.kt b/privacysandbox/activity/activity-client/src/androidTest/java/androidx/privacysandbox/activity/client/TestActivity.kt
new file mode 100644
index 0000000..74ffb5d
--- /dev/null
+++ b/privacysandbox/activity/activity-client/src/androidTest/java/androidx/privacysandbox/activity/client/TestActivity.kt
@@ -0,0 +1,21 @@
+/*
+ * 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.activity.client
+
+import androidx.appcompat.app.AppCompatActivity
+
+class TestActivity : AppCompatActivity()
diff --git a/privacysandbox/activity/activity-client/src/main/java/androidx/privacysandbox/activity/client/SdkActivityLaunchers.kt b/privacysandbox/activity/activity-client/src/main/java/androidx/privacysandbox/activity/client/SdkActivityLaunchers.kt
new file mode 100644
index 0000000..2dd726e
--- /dev/null
+++ b/privacysandbox/activity/activity-client/src/main/java/androidx/privacysandbox/activity/client/SdkActivityLaunchers.kt
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+@file:JvmName("SdkActivityLaunchers")
+
+package androidx.privacysandbox.activity.client
+
+import android.app.Activity
+import android.os.Bundle
+import android.os.IBinder
+import androidx.core.os.BundleCompat
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.privacysandbox.activity.core.ISdkActivityLauncher
+import androidx.privacysandbox.activity.core.ISdkActivityLauncherCallback
+import androidx.privacysandbox.activity.core.ProtocolConstants.SDK_ACTIVITY_LAUNCHER_BINDER_KEY
+import androidx.privacysandbox.activity.core.SdkActivityLauncher
+import androidx.privacysandbox.sdkruntime.client.SdkSandboxManagerCompat
+import java.util.concurrent.atomic.AtomicReference
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * Returns an SdkActivityLauncher that launches activities on behalf of an SDK by using this
+ * activity as a starting context.
+ *
+ * @param T the current activity from which new SDK activities will be launched. If this activity is
+ * destroyed any further SDK activity launches will simply be ignored.
+ * @param allowLaunch predicate called each time an activity is about to be launched by the
+ * SDK, the activity will only be launched if it returns true.
+ */
+fun <T> T.createSdkActivityLauncher(
+ allowLaunch: () -> Boolean
+): LocalSdkActivityLauncher<T>
+ where T : Activity, T : LifecycleOwner {
+ val cancellationJob = Job(parent = lifecycleScope.coroutineContext[Job])
+ val launcher = LocalSdkActivityLauncherImpl(
+ activity = this,
+ allowLaunch = allowLaunch,
+ cancellationJob.cancel() },
+ )
+ cancellationJob.invokeOnCompletion {
+ launcher.dispose()
+ }
+ return launcher
+}
+
+/**
+ * Returns a [Bundle] with the information necessary to recreate this launcher.
+ * Possibly in a different process.
+ */
+fun SdkActivityLauncher.toLauncherInfo(): Bundle {
+ val binderDelegate = SdkActivityLauncherBinderDelegate(this)
+ return Bundle().also { bundle ->
+ BundleCompat.putBinder(bundle, SDK_ACTIVITY_LAUNCHER_BINDER_KEY, binderDelegate)
+ }
+}
+
+/**
+ * Local implementation of an SDK Activity launcher.
+ *
+ * It allows callers in the app process to dispose resources used to launch SDK activities.
+ */
+interface LocalSdkActivityLauncher<T> : SdkActivityLauncher where T : Activity, T : LifecycleOwner {
+ /**
+ * Clears references used to launch activities.
+ *
+ * After this method is called all further attempts to launch activities wil be rejected.
+ * Doesn't do anything if the launcher was already disposed of.
+ */
+ fun dispose()
+}
+
+private class LocalSdkActivityLauncherImpl<T>(
+ activity: T,
+ allowLaunch: () -> Boolean,
+ onDispose: () -> Unit
+) : LocalSdkActivityLauncher<T> where T : Activity, T : LifecycleOwner {
+
+ /** Internal state for [LocalSdkActivityLauncher], cleared when the launcher is disposed. */
+ private class LocalLauncherState<T>(
+ val activity: T,
+ val allowLaunch: () -> Boolean,
+ val sdkSandboxManager: SdkSandboxManagerCompat,
+ val onDispose: () -> Unit
+ ) where T : Activity, T : LifecycleOwner
+
+ private val stateReference: AtomicReference<LocalLauncherState<T>?> =
+ AtomicReference<LocalLauncherState<T>?>(
+ LocalLauncherState(
+ activity,
+ allowLaunch,
+ SdkSandboxManagerCompat.from(activity),
+ onDispose
+ )
+ )
+
+ override suspend fun launchSdkActivity(
+ sdkActivityHandlerToken: IBinder
+ ): Boolean {
+ val state = stateReference.get() ?: return false
+ return withContext(Dispatchers.Main.immediate) {
+ state.run {
+ allowLaunch().also { didAllowLaunch ->
+ if (didAllowLaunch) {
+ sdkSandboxManager.startSdkSandboxActivity(activity, sdkActivityHandlerToken)
+ }
+ }
+ }
+ }
+ }
+
+ override fun dispose() {
+ stateReference.getAndSet(null)?.run {
+ onDispose()
+ }
+ }
+}
+
+private class SdkActivityLauncherBinderDelegate(private val launcher: SdkActivityLauncher) :
+ ISdkActivityLauncher.Stub() {
+
+ private val coroutineScope = CoroutineScope(Dispatchers.Main)
+
+ override fun launchSdkActivity(
+ sdkActivityHandlerToken: IBinder?,
+ callback: ISdkActivityLauncherCallback?
+ ) {
+ requireNotNull(sdkActivityHandlerToken)
+ requireNotNull(callback)
+
+ coroutineScope.launch {
+ val accepted = try {
+ launcher.launchSdkActivity(sdkActivityHandlerToken)
+ } catch (t: Throwable) {
+ callback.onLaunchError(t.message ?: "Unknown error launching SDK activity.")
+ return@launch
+ }
+
+ if (accepted) {
+ callback.onLaunchAccepted(sdkActivityHandlerToken)
+ } else {
+ callback.onLaunchRejected(sdkActivityHandlerToken)
+ }
+ }
+ }
+}
diff --git a/privacysandbox/activity/activity-core/api/aidlRelease/current/androidx/privacysandbox/activity/core/ISdkActivityLauncher.aidl b/privacysandbox/activity/activity-core/api/aidlRelease/current/androidx/privacysandbox/activity/core/ISdkActivityLauncher.aidl
new file mode 100644
index 0000000..f5fc693
--- /dev/null
+++ b/privacysandbox/activity/activity-core/api/aidlRelease/current/androidx/privacysandbox/activity/core/ISdkActivityLauncher.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package androidx.privacysandbox.activity.core;
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
+interface ISdkActivityLauncher {
+ oneway void launchSdkActivity(in IBinder sdkActivityHandlerToken, androidx.privacysandbox.activity.core.ISdkActivityLauncherCallback callback) = 1;
+}
diff --git a/privacysandbox/activity/activity-core/api/aidlRelease/current/androidx/privacysandbox/activity/core/ISdkActivityLauncherCallback.aidl b/privacysandbox/activity/activity-core/api/aidlRelease/current/androidx/privacysandbox/activity/core/ISdkActivityLauncherCallback.aidl
new file mode 100644
index 0000000..baf0647
--- /dev/null
+++ b/privacysandbox/activity/activity-core/api/aidlRelease/current/androidx/privacysandbox/activity/core/ISdkActivityLauncherCallback.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package androidx.privacysandbox.activity.core;
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
+interface ISdkActivityLauncherCallback {
+ oneway void onLaunchAccepted(in IBinder sdkActivityHandlerToken) = 1;
+ oneway void onLaunchRejected(in IBinder sdkActivityHandlerToken) = 2;
+ oneway void onLaunchError(String message) = 3;
+}
diff --git a/privacysandbox/activity/activity-core/api/current.txt b/privacysandbox/activity/activity-core/api/current.txt
new file mode 100644
index 0000000..9051c68
--- /dev/null
+++ b/privacysandbox/activity/activity-core/api/current.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.privacysandbox.activity.core {
+
+ public interface SdkActivityLauncher {
+ method public suspend Object? launchSdkActivity(android.os.IBinder sdkActivityHandlerToken, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
+ }
+
+}
+
diff --git a/privacysandbox/activity/activity-core/api/res-current.txt b/privacysandbox/activity/activity-core/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/privacysandbox/activity/activity-core/api/res-current.txt
diff --git a/privacysandbox/activity/activity-core/api/restricted_current.txt b/privacysandbox/activity/activity-core/api/restricted_current.txt
new file mode 100644
index 0000000..9051c68
--- /dev/null
+++ b/privacysandbox/activity/activity-core/api/restricted_current.txt
@@ -0,0 +1,9 @@
+// Signature format: 4.0
+package androidx.privacysandbox.activity.core {
+
+ public interface SdkActivityLauncher {
+ method public suspend Object? launchSdkActivity(android.os.IBinder sdkActivityHandlerToken, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
+ }
+
+}
+
diff --git a/privacysandbox/activity/activity-core/build.gradle b/privacysandbox/activity/activity-core/build.gradle
new file mode 100644
index 0000000..b52889a
--- /dev/null
+++ b/privacysandbox/activity/activity-core/build.gradle
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 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.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+ id("androidx.stableaidl")
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+ api("androidx.annotation:annotation:1.1.0")
+}
+
+android {
+ namespace "androidx.privacysandbox.activity.core"
+ buildFeatures {
+ aidl = true
+ }
+ buildTypes.all {
+ stableAidl {
+ version 1
+ }
+ }
+ defaultConfig {
+ minSdk 21
+ }
+}
+
+androidx {
+ name = "androidx.privacysandbox.activity:activity-core"
+ type = LibraryType.PUBLISHED_LIBRARY
+ inceptionYear = "2023"
+ description = "Core utilities for Activities in the Privacy Sandbox."
+}
diff --git a/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/ProtocolConstants.kt b/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/ProtocolConstants.kt
new file mode 100644
index 0000000..b0936c5
--- /dev/null
+++ b/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/ProtocolConstants.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.activity.core
+
+import androidx.annotation.RestrictTo
+
+/**
+ * Constants shared between Activity library artifacts to establish an IPC protocol across library
+ * versions. Adding new constants is allowed, but **never change the value of a constant** or
+ * you'll break compatibility between library versions.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+object ProtocolConstants {
+ const val SDK_ACTIVITY_LAUNCHER_BINDER_KEY = "sdkActivityLauncherBinderKey"
+}
diff --git a/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/SdkActivityLauncher.kt b/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/SdkActivityLauncher.kt
new file mode 100644
index 0000000..8fe6567
--- /dev/null
+++ b/privacysandbox/activity/activity-core/src/main/java/androidx/privacysandbox/activity/core/SdkActivityLauncher.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.activity.core
+
+import android.os.IBinder
+
+/**
+ * Interface that allows SDKs running in the Privacy Sandbox to launch activities.
+ *
+ * Apps can create launchers by calling
+ * [createActivityLauncher][androidx.privacysandbox.activity.client.createSdkActivityLauncher]
+ * from one of their activities.
+ *
+ * To send an [SdkActivityLauncher] to another process, they can call
+ * [toLauncherInfo][androidx.privacysandbox.activity.client.toLauncherInfo]
+ * and send the resulting bundle.
+ *
+ * SDKs can create launchers from an app-provided bundle by calling
+ * [createFromLauncherInfo][androidx.privacysandbox.activity.provider.SdkActivityLauncherFactory.createFromLauncherInfo].
+ */
+interface SdkActivityLauncher {
+
+ /**
+ * Tries to launch a new SDK activity using the given [sdkActivityHandlerToken],
+ * assumed to be registered in the [SdkSandboxControllerCompat][androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat].
+ *
+ * Returns true if the SDK activity intent was sent, false if the launch was rejected for any
+ * reason.
+ */
+ suspend fun launchSdkActivity(sdkActivityHandlerToken: IBinder): Boolean
+}
diff --git a/privacysandbox/activity/activity-core/src/main/stableAidl/androidx/privacysandbox/activity/core/ISdkActivityLauncher.aidl b/privacysandbox/activity/activity-core/src/main/stableAidl/androidx/privacysandbox/activity/core/ISdkActivityLauncher.aidl
new file mode 100644
index 0000000..a3c69e2
--- /dev/null
+++ b/privacysandbox/activity/activity-core/src/main/stableAidl/androidx/privacysandbox/activity/core/ISdkActivityLauncher.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 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.activity.core;
+
+import androidx.privacysandbox.activity.core.ISdkActivityLauncherCallback;
+
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
+oneway interface ISdkActivityLauncher {
+ void launchSdkActivity(
+ in IBinder sdkActivityHandlerToken,
+ ISdkActivityLauncherCallback callback) = 1;
+}
\ No newline at end of file
diff --git a/privacysandbox/activity/activity-core/src/main/stableAidl/androidx/privacysandbox/activity/core/ISdkActivityLauncherCallback.aidl b/privacysandbox/activity/activity-core/src/main/stableAidl/androidx/privacysandbox/activity/core/ISdkActivityLauncherCallback.aidl
new file mode 100644
index 0000000..2a3c245
--- /dev/null
+++ b/privacysandbox/activity/activity-core/src/main/stableAidl/androidx/privacysandbox/activity/core/ISdkActivityLauncherCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 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.activity.core;
+
+@JavaPassthrough(annotation="@androidx.annotation.RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY)")
+oneway interface ISdkActivityLauncherCallback {
+ void onLaunchAccepted(in IBinder sdkActivityHandlerToken) = 1;
+ void onLaunchRejected(in IBinder sdkActivityHandlerToken) = 2;
+ void onLaunchError(String message) = 3;
+}
\ No newline at end of file
diff --git a/privacysandbox/activity/activity-provider/api/current.txt b/privacysandbox/activity/activity-provider/api/current.txt
new file mode 100644
index 0000000..ddf6b94
--- /dev/null
+++ b/privacysandbox/activity/activity-provider/api/current.txt
@@ -0,0 +1,10 @@
+// Signature format: 4.0
+package androidx.privacysandbox.activity.provider {
+
+ public final class SdkActivityLauncherFactory {
+ method public static androidx.privacysandbox.activity.core.SdkActivityLauncher fromLauncherInfo(android.os.Bundle launcherInfo);
+ field public static final androidx.privacysandbox.activity.provider.SdkActivityLauncherFactory INSTANCE;
+ }
+
+}
+
diff --git a/privacysandbox/activity/activity-provider/api/res-current.txt b/privacysandbox/activity/activity-provider/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/privacysandbox/activity/activity-provider/api/res-current.txt
diff --git a/privacysandbox/activity/activity-provider/api/restricted_current.txt b/privacysandbox/activity/activity-provider/api/restricted_current.txt
new file mode 100644
index 0000000..ddf6b94
--- /dev/null
+++ b/privacysandbox/activity/activity-provider/api/restricted_current.txt
@@ -0,0 +1,10 @@
+// Signature format: 4.0
+package androidx.privacysandbox.activity.provider {
+
+ public final class SdkActivityLauncherFactory {
+ method public static androidx.privacysandbox.activity.core.SdkActivityLauncher fromLauncherInfo(android.os.Bundle launcherInfo);
+ field public static final androidx.privacysandbox.activity.provider.SdkActivityLauncherFactory INSTANCE;
+ }
+
+}
+
diff --git a/privacysandbox/activity/activity-provider/build.gradle b/privacysandbox/activity/activity-provider/build.gradle
new file mode 100644
index 0000000..856130b
--- /dev/null
+++ b/privacysandbox/activity/activity-provider/build.gradle
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+ api("androidx.annotation:annotation:1.1.0")
+
+ implementation(project(":privacysandbox:activity:activity-core"))
+ implementation("androidx.core:core:1.12.0")
+ implementation(libs.kotlinCoroutinesCore)
+
+ androidTestImplementation(project(":privacysandbox:activity:activity-client"))
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.truth)
+}
+
+android {
+ namespace "androidx.privacysandbox.activity.provider"
+ defaultConfig {
+ minSdk 21
+ }
+}
+
+androidx {
+ name = "androidx.privacysandbox.activity:activity-provider"
+ type = LibraryType.PUBLISHED_LIBRARY
+ inceptionYear = "2023"
+ description = "Utilities for launchig Activities from the Privacy Sandbox."
+}
diff --git a/privacysandbox/activity/activity-provider/src/androidTest/java/androidx/privacysandbox/activity/provider/SdkActivityLauncherBundlingTest.kt b/privacysandbox/activity/activity-provider/src/androidTest/java/androidx/privacysandbox/activity/provider/SdkActivityLauncherBundlingTest.kt
new file mode 100644
index 0000000..4659813
--- /dev/null
+++ b/privacysandbox/activity/activity-provider/src/androidTest/java/androidx/privacysandbox/activity/provider/SdkActivityLauncherBundlingTest.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.activity.provider
+
+import android.os.Binder
+import android.os.IBinder
+import androidx.privacysandbox.activity.client.toLauncherInfo
+import androidx.privacysandbox.activity.core.SdkActivityLauncher
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SdkActivityLauncherBundlingTest {
+
+ @Test
+ fun unbundledSdkActivityLauncher_launchesActivities(): Unit = runBlocking {
+ val launcher = TestSdkActivityLauncher()
+ val launcherInfo = launcher.toLauncherInfo()
+
+ val unbundledLauncher = SdkActivityLauncherFactory.fromLauncherInfo(launcherInfo)
+ val token = Binder()
+ val result = unbundledLauncher.launchSdkActivity(token)
+
+ assertThat(result).isTrue()
+ assertThat(launcher.tokensReceived).containsExactly(token)
+ }
+
+ @Test
+ fun unbundledSdkActivityLauncher_rejectsActivityLaunches(): Unit = runBlocking {
+ val launcher = TestSdkActivityLauncher()
+ launcher.allowActivityLaunches = false
+ val launcherInfo = launcher.toLauncherInfo()
+
+ val unbundledLauncher = SdkActivityLauncherFactory.fromLauncherInfo(launcherInfo)
+ val token = Binder()
+ val result = unbundledLauncher.launchSdkActivity(token)
+
+ assertThat(result).isFalse()
+ assertThat(launcher.tokensReceived).containsExactly(token)
+ }
+
+ class TestSdkActivityLauncher : SdkActivityLauncher {
+ var allowActivityLaunches: Boolean = true
+
+ var tokensReceived = mutableListOf<IBinder>()
+
+ override suspend fun launchSdkActivity(sdkActivityHandlerToken: IBinder):
+ Boolean {
+ tokensReceived.add(sdkActivityHandlerToken)
+ return allowActivityLaunches
+ }
+ }
+}
diff --git a/privacysandbox/activity/activity-provider/src/main/java/androidx/privacysandbox/activity/provider/SdkActivityLauncherFactory.kt b/privacysandbox/activity/activity-provider/src/main/java/androidx/privacysandbox/activity/provider/SdkActivityLauncherFactory.kt
new file mode 100644
index 0000000..8e53590
--- /dev/null
+++ b/privacysandbox/activity/activity-provider/src/main/java/androidx/privacysandbox/activity/provider/SdkActivityLauncherFactory.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.activity.provider
+
+import android.os.Bundle
+import android.os.IBinder
+import androidx.core.os.BundleCompat
+import androidx.privacysandbox.activity.core.ISdkActivityLauncher
+import androidx.privacysandbox.activity.core.ISdkActivityLauncherCallback
+import androidx.privacysandbox.activity.core.ProtocolConstants.SDK_ACTIVITY_LAUNCHER_BINDER_KEY
+import androidx.privacysandbox.activity.core.SdkActivityLauncher
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+object SdkActivityLauncherFactory {
+
+ /**
+ * Creates a [SdkActivityLauncher] using the given [launcherInfo] Bundle.
+ *
+ * You can create such a Bundle by calling [toLauncherInfo][androidx.privacysandbox.activity.client.toLauncherInfo].
+ * A [launcherInfo] is expected to have a valid SdkActivityLauncher Binder with
+ * `"sdkActivityLauncherBinderKey"` for a key, [IllegalArgumentException] is thrown otherwise.
+ */
+ @JvmStatic
+ fun fromLauncherInfo(launcherInfo: Bundle): SdkActivityLauncher {
+ val remote: ISdkActivityLauncher? = ISdkActivityLauncher.Stub.asInterface(
+ BundleCompat.getBinder(launcherInfo, SDK_ACTIVITY_LAUNCHER_BINDER_KEY)
+ )
+ requireNotNull(remote) { "Invalid SdkActivityLauncher info bundle." }
+ return SdkActivityLauncherProxy(remote)
+ }
+
+ private class SdkActivityLauncherProxy(
+ private val remote: ISdkActivityLauncher
+ ) : SdkActivityLauncher {
+ override suspend fun launchSdkActivity(sdkActivityHandlerToken: IBinder): Boolean =
+ suspendCancellableCoroutine {
+ remote.launchSdkActivity(
+ sdkActivityHandlerToken,
+ object : ISdkActivityLauncherCallback.Stub() {
+ override fun onLaunchAccepted(sdkActivityHandlerToken: IBinder?) {
+ it.resume(true)
+ }
+
+ override fun onLaunchRejected(sdkActivityHandlerToken: IBinder?) {
+ it.resume(false)
+ }
+
+ override fun onLaunchError(message: String?) {
+ it.resumeWithException(RuntimeException(message))
+ }
+ })
+ }
+ }
+}
diff --git a/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/CompilationTestHelper.kt b/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/CompilationTestHelper.kt
index 46db8fff..40089ca 100644
--- a/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/CompilationTestHelper.kt
+++ b/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/CompilationTestHelper.kt
@@ -116,10 +116,23 @@
assertThat(getShortErrorMessages()).containsExactly(*errors)
}
- private fun getRawErrorMessages() =
- (result.diagnostics[Diagnostic.Kind.ERROR] ?: emptyList()) +
- (result.diagnostics[Diagnostic.Kind.WARNING] ?: emptyList()) +
+ private fun getRawErrorMessages(): List<DiagnosticMessage> {
+ // Filter SdkActivityLauncher deprecation warnings. Our tests currently use the old version
+ // so the warnings are expected.
+ // TODO(b/307696996) - Remove this once the generator uses the new version exclusively.
+ val warningsToIgnore = listOf(
+ "'SdkActivityLauncher' is deprecated.",
+ "'SdkActivityLauncherFactory' is deprecated.",
+ "'toLauncherInfo(): Bundle' is deprecated.",
+ )
+ val filteredWarnings = result.diagnostics[Diagnostic.Kind.WARNING]?.filter { warning ->
+ !warningsToIgnore.any { warning.msg.contains(it) }
+ } ?: emptyList()
+
+ return (result.diagnostics[Diagnostic.Kind.ERROR] ?: emptyList()) +
+ filteredWarnings +
(result.diagnostics[Diagnostic.Kind.MANDATORY_WARNING] ?: emptyList())
+ }
private fun getShortErrorMessages() =
result.diagnostics[Diagnostic.Kind.ERROR]?.map(DiagnosticMessage::msg)
diff --git a/privacysandbox/ui/ui-client/api/current.txt b/privacysandbox/ui/ui-client/api/current.txt
index 6db1a94..3e1cb8f 100644
--- a/privacysandbox/ui/ui-client/api/current.txt
+++ b/privacysandbox/ui/ui-client/api/current.txt
@@ -1,8 +1,8 @@
// Signature format: 4.0
package androidx.privacysandbox.ui.client {
- public interface LocalSdkActivityLauncher<T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> extends androidx.privacysandbox.ui.core.SdkActivityLauncher {
- method public void dispose();
+ @Deprecated public interface LocalSdkActivityLauncher<T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> extends androidx.privacysandbox.ui.core.SdkActivityLauncher {
+ method @Deprecated public void dispose();
}
public final class SandboxedUiAdapterFactory {
@@ -11,8 +11,8 @@
}
public final class SdkActivityLaunchers {
- method public static <T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> androidx.privacysandbox.ui.client.LocalSdkActivityLauncher<T> createSdkActivityLauncher(T, kotlin.jvm.functions.Function0<java.lang.Boolean> allowLaunch);
- method public static android.os.Bundle toLauncherInfo(androidx.privacysandbox.ui.core.SdkActivityLauncher);
+ method @Deprecated public static <T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> androidx.privacysandbox.ui.client.LocalSdkActivityLauncher<T> createSdkActivityLauncher(T, kotlin.jvm.functions.Function0<java.lang.Boolean> allowLaunch);
+ method @Deprecated public static android.os.Bundle toLauncherInfo(androidx.privacysandbox.ui.core.SdkActivityLauncher);
}
}
diff --git a/privacysandbox/ui/ui-client/api/restricted_current.txt b/privacysandbox/ui/ui-client/api/restricted_current.txt
index 6db1a94..3e1cb8f 100644
--- a/privacysandbox/ui/ui-client/api/restricted_current.txt
+++ b/privacysandbox/ui/ui-client/api/restricted_current.txt
@@ -1,8 +1,8 @@
// Signature format: 4.0
package androidx.privacysandbox.ui.client {
- public interface LocalSdkActivityLauncher<T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> extends androidx.privacysandbox.ui.core.SdkActivityLauncher {
- method public void dispose();
+ @Deprecated public interface LocalSdkActivityLauncher<T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> extends androidx.privacysandbox.ui.core.SdkActivityLauncher {
+ method @Deprecated public void dispose();
}
public final class SandboxedUiAdapterFactory {
@@ -11,8 +11,8 @@
}
public final class SdkActivityLaunchers {
- method public static <T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> androidx.privacysandbox.ui.client.LocalSdkActivityLauncher<T> createSdkActivityLauncher(T, kotlin.jvm.functions.Function0<java.lang.Boolean> allowLaunch);
- method public static android.os.Bundle toLauncherInfo(androidx.privacysandbox.ui.core.SdkActivityLauncher);
+ method @Deprecated public static <T extends android.app.Activity & androidx.lifecycle.LifecycleOwner> androidx.privacysandbox.ui.client.LocalSdkActivityLauncher<T> createSdkActivityLauncher(T, kotlin.jvm.functions.Function0<java.lang.Boolean> allowLaunch);
+ method @Deprecated public static android.os.Bundle toLauncherInfo(androidx.privacysandbox.ui.core.SdkActivityLauncher);
}
}
diff --git a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/CreateSdkActivityLauncherTest.kt b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/CreateSdkActivityLauncherTest.kt
index 55c5a54..829a41a 100644
--- a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/CreateSdkActivityLauncherTest.kt
+++ b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/CreateSdkActivityLauncherTest.kt
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// TODO(b/307696996) Remove this file when activity library is released.
+@file:Suppress("DEPRECATION")
+
package androidx.privacysandbox.ui.client.test
import android.app.Activity
diff --git a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SdkActivityLaunchers.kt b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SdkActivityLaunchers.kt
index d8a6f94..5197cfd 100644
--- a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SdkActivityLaunchers.kt
+++ b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SdkActivityLaunchers.kt
@@ -15,6 +15,8 @@
*/
@file:JvmName("SdkActivityLaunchers")
+// TODO(b/307696996) Remove this file when activity library is released.
+@file:Suppress("DEPRECATION")
package androidx.privacysandbox.ui.client
@@ -45,6 +47,10 @@
* @param allowLaunch predicate called each time an activity is about to be launched by the
* SDK, the activity will only be launched if it returns true.
*/
+@Deprecated("Use the Privacy Sandbox Activity library version instead.",
+ ReplaceWith(
+ expression = "createSdkActivityLauncher",
+ imports = arrayOf("androidx.privacysandbox.activity.client.createSdkActivityLauncher")))
fun <T> T.createSdkActivityLauncher(
allowLaunch: () -> Boolean
): LocalSdkActivityLauncher<T>
@@ -65,6 +71,10 @@
* Returns a [Bundle] with the information necessary to recreate this launcher.
* Possibly in a different process.
*/
+@Deprecated("Use the Privacy Sandbox Activity library version instead.",
+ ReplaceWith(
+ expression = "toLauncherInfo",
+ imports = arrayOf("androidx.privacysandbox.activity.client.toLauncherInfo")))
fun SdkActivityLauncher.toLauncherInfo(): Bundle {
val binderDelegate = SdkActivityLauncherBinderDelegate(this)
return Bundle().also { bundle ->
@@ -77,6 +87,10 @@
*
* It allows callers in the app process to dispose resources used to launch SDK activities.
*/
+@Deprecated("Use the Privacy Sandbox Activity library version instead.",
+ ReplaceWith(
+ expression = "LocalSdkActivityLauncher",
+ imports = arrayOf("androidx.privacysandbox.activity.client.LocalSdkActivityLauncher")))
interface LocalSdkActivityLauncher<T> : SdkActivityLauncher where T : Activity, T : LifecycleOwner {
/**
* Clears references used to launch activities.
diff --git a/privacysandbox/ui/ui-core/api/current.txt b/privacysandbox/ui/ui-core/api/current.txt
index 2537c3e..5ab678d 100644
--- a/privacysandbox/ui/ui-core/api/current.txt
+++ b/privacysandbox/ui/ui-core/api/current.txt
@@ -20,8 +20,8 @@
method public void onSessionOpened(androidx.privacysandbox.ui.core.SandboxedUiAdapter.Session session);
}
- public interface SdkActivityLauncher {
- method public suspend Object? launchSdkActivity(android.os.IBinder sdkActivityHandlerToken, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
+ @Deprecated public interface SdkActivityLauncher {
+ method @Deprecated public suspend Object? launchSdkActivity(android.os.IBinder sdkActivityHandlerToken, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
}
public final class SdkRuntimeUiLibVersions {
diff --git a/privacysandbox/ui/ui-core/api/restricted_current.txt b/privacysandbox/ui/ui-core/api/restricted_current.txt
index 2537c3e..5ab678d 100644
--- a/privacysandbox/ui/ui-core/api/restricted_current.txt
+++ b/privacysandbox/ui/ui-core/api/restricted_current.txt
@@ -20,8 +20,8 @@
method public void onSessionOpened(androidx.privacysandbox.ui.core.SandboxedUiAdapter.Session session);
}
- public interface SdkActivityLauncher {
- method public suspend Object? launchSdkActivity(android.os.IBinder sdkActivityHandlerToken, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
+ @Deprecated public interface SdkActivityLauncher {
+ method @Deprecated public suspend Object? launchSdkActivity(android.os.IBinder sdkActivityHandlerToken, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
}
public final class SdkRuntimeUiLibVersions {
diff --git a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SdkActivityLauncher.kt b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SdkActivityLauncher.kt
index 9134f7e..72ac835 100644
--- a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SdkActivityLauncher.kt
+++ b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SdkActivityLauncher.kt
@@ -32,6 +32,11 @@
* SDKs can create launchers from an app-provided bundle by calling
* [createFromLauncherInfo][androidx.privacysandbox.ui.provider.SdkActivityLauncherFactory.createFromLauncherInfo].
*/
+@Deprecated("Use the Privacy Sandbox Activity library version instead.",
+ ReplaceWith(
+ expression = "SdkActivityLauncher",
+ imports = arrayOf("androidx.privacysandbox.activity.core.SdkActivityLauncher")))
+// TODO(b/307696996) Remove this file when activity library is released.
interface SdkActivityLauncher {
/**
diff --git a/privacysandbox/ui/ui-provider/api/current.txt b/privacysandbox/ui/ui-provider/api/current.txt
index 1c7512c..0ba0f20 100644
--- a/privacysandbox/ui/ui-provider/api/current.txt
+++ b/privacysandbox/ui/ui-provider/api/current.txt
@@ -5,9 +5,9 @@
method public static android.os.Bundle toCoreLibInfo(androidx.privacysandbox.ui.core.SandboxedUiAdapter, android.content.Context context);
}
- public final class SdkActivityLauncherFactory {
- method public static androidx.privacysandbox.ui.core.SdkActivityLauncher fromLauncherInfo(android.os.Bundle launcherInfo);
- field public static final androidx.privacysandbox.ui.provider.SdkActivityLauncherFactory INSTANCE;
+ @Deprecated public final class SdkActivityLauncherFactory {
+ method @Deprecated public static androidx.privacysandbox.ui.core.SdkActivityLauncher fromLauncherInfo(android.os.Bundle launcherInfo);
+ field @Deprecated public static final androidx.privacysandbox.ui.provider.SdkActivityLauncherFactory INSTANCE;
}
}
diff --git a/privacysandbox/ui/ui-provider/api/restricted_current.txt b/privacysandbox/ui/ui-provider/api/restricted_current.txt
index 1c7512c..0ba0f20 100644
--- a/privacysandbox/ui/ui-provider/api/restricted_current.txt
+++ b/privacysandbox/ui/ui-provider/api/restricted_current.txt
@@ -5,9 +5,9 @@
method public static android.os.Bundle toCoreLibInfo(androidx.privacysandbox.ui.core.SandboxedUiAdapter, android.content.Context context);
}
- public final class SdkActivityLauncherFactory {
- method public static androidx.privacysandbox.ui.core.SdkActivityLauncher fromLauncherInfo(android.os.Bundle launcherInfo);
- field public static final androidx.privacysandbox.ui.provider.SdkActivityLauncherFactory INSTANCE;
+ @Deprecated public final class SdkActivityLauncherFactory {
+ method @Deprecated public static androidx.privacysandbox.ui.core.SdkActivityLauncher fromLauncherInfo(android.os.Bundle launcherInfo);
+ field @Deprecated public static final androidx.privacysandbox.ui.provider.SdkActivityLauncherFactory INSTANCE;
}
}
diff --git a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/SdkActivityLauncherFactory.kt b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/SdkActivityLauncherFactory.kt
index 5e72d7a..409bd36 100644
--- a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/SdkActivityLauncherFactory.kt
+++ b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/SdkActivityLauncherFactory.kt
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// TODO(b/307696996) Remove this file when activity library is released.
+@file:Suppress("DEPRECATION")
+
package androidx.privacysandbox.ui.provider
import android.os.Bundle
@@ -27,6 +30,10 @@
import kotlin.coroutines.resumeWithException
import kotlinx.coroutines.suspendCancellableCoroutine
+@Deprecated("Use the Privacy Sandbox Activity library version instead.",
+ ReplaceWith(
+ expression = "SdkActivityLauncherFactory",
+ imports = arrayOf("androidx.privacysandbox.activity.provider.SdkActivityLauncherFactory")))
object SdkActivityLauncherFactory {
/**
diff --git a/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/activity/SdkActivityLauncherBundlingTest.kt b/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/activity/SdkActivityLauncherBundlingTest.kt
index 66fdcdf..6b5b722 100644
--- a/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/activity/SdkActivityLauncherBundlingTest.kt
+++ b/privacysandbox/ui/ui-tests/src/androidTest/java/androidx/privacysandbox/ui/tests/activity/SdkActivityLauncherBundlingTest.kt
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+// TODO(b/307696996) Remove this file when activity library is released.
+@file:Suppress("DEPRECATION")
+
package androidx.privacysandbox.ui.tests.activity
import android.os.Binder
diff --git a/settings.gradle b/settings.gradle
index e7da77a..38ea422 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -821,6 +821,9 @@
includeProject(":preference:preference", [BuildType.MAIN])
includeProject(":preference:preference-ktx", [BuildType.MAIN])
includeProject(":print:print", [BuildType.MAIN])
+includeProject(":privacysandbox:activity:activity-client", [BuildType.MAIN])
+includeProject(":privacysandbox:activity:activity-core", [BuildType.MAIN])
+includeProject(":privacysandbox:activity:activity-provider", [BuildType.MAIN])
includeProject(":privacysandbox:ads:ads-adservices", [BuildType.MAIN])
includeProject(":privacysandbox:ads:ads-adservices-java", [BuildType.MAIN])
includeProject(":privacysandbox:plugins:plugins-privacysandbox-library", [BuildType.MAIN])