Allow Bundles in Privacy Sandbox APIs.

Relnote: "Bundles are now accepted as valid parameters and return types
    in annotated interfaces and values."
Test: ./gradlew privacysandbox:tools:tools-{core,apigenerator,apicompiler}:tests
Change-Id: I52995e422051e15849b0e0888e5e7ac89ea475ae
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkApiCompilerDiffTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkApiCompilerDiffTest.kt
index 437f221..0e952c2 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkApiCompilerDiffTest.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/FullFeaturedSdkApiCompilerDiffTest.kt
@@ -32,6 +32,7 @@
         "com/mysdk/IMySecondInterface.java",
         "com/mysdk/IMyUiInterface.java",
         "com/mysdk/IMyUiInterfaceCoreLibInfoAndBinderWrapper.java",
+        "com/mysdk/IBundleTransactionCallback.java",
         "com/mysdk/IMyUiInterfaceTransactionCallback.java",
         "com/mysdk/IMySecondInterfaceTransactionCallback.java",
         "com/mysdk/ISdkActivityLauncherTransactionCallback.java",
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/input/com/mysdk/MySdk.kt b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/input/com/mysdk/MySdk.kt
index af14632..e2acc1b 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/input/com/mysdk/MySdk.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/input/com/mysdk/MySdk.kt
@@ -1,5 +1,6 @@
 package com.mysdk
 
+import android.os.Bundle
 import androidx.privacysandbox.tools.PrivacySandboxCallback
 import androidx.privacysandbox.tools.PrivacySandboxInterface
 import androidx.privacysandbox.tools.PrivacySandboxService
@@ -58,6 +59,8 @@
 interface MySecondInterface {
     suspend fun doIntStuff(x: List<Int>): List<Int>
 
+    suspend fun doBundleStuff(x: Bundle): Bundle
+
     suspend fun doCharStuff(x: List<Char>): List<Char>
 
     suspend fun doFloatStuff(x: List<Float>): List<Float>
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/MySecondInterfaceStubDelegate.kt b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/MySecondInterfaceStubDelegate.kt
index af61158b..ac985f7 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/MySecondInterfaceStubDelegate.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/test-data/fullfeaturedsdk/output/com/mysdk/MySecondInterfaceStubDelegate.kt
@@ -1,6 +1,7 @@
 package com.mysdk
 
 import android.content.Context
+import android.os.Bundle
 import com.mysdk.PrivacySandboxThrowableParcelConverter.toThrowableParcel
 import kotlin.Array
 import kotlin.BooleanArray
@@ -34,6 +35,20 @@
     transactionCallback.onCancellable(cancellationSignal)
   }
 
+  public override fun doBundleStuff(x: Bundle, transactionCallback: IBundleTransactionCallback) {
+    val job = coroutineScope.launch {
+      try {
+        val result = delegate.doBundleStuff(x)
+        transactionCallback.onSuccess(result)
+      }
+      catch (t: Throwable) {
+        transactionCallback.onFailure(toThrowableParcel(t))
+      }
+    }
+    val cancellationSignal = TransportCancellationCallback() { job.cancel() }
+    transactionCallback.onCancellable(cancellationSignal)
+  }
+
   public override fun doCharStuff(x: CharArray, transactionCallback: IListCharTransactionCallback) {
     val job = coroutineScope.launch {
       try {
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorDiffTest.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorDiffTest.kt
index 832baa1..ab5025f 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorDiffTest.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/PrimitivesApiGeneratorDiffTest.kt
@@ -25,6 +25,7 @@
     override val relativePathsToExpectedAidlClasses = listOf(
         "com/mysdk/ITestSandboxSdk.java",
         "com/mysdk/IBooleanTransactionCallback.java",
+        "com/mysdk/IBundleTransactionCallback.java",
         "com/mysdk/ICancellationSignal.java",
         "com/mysdk/IUnitTransactionCallback.java",
         "com/mysdk/IListLongTransactionCallback.java",
@@ -32,6 +33,7 @@
         "com/mysdk/IListShortTransactionCallback.java",
         "com/mysdk/IListStringTransactionCallback.java",
         "com/mysdk/IListBooleanTransactionCallback.java",
+        "com/mysdk/IListBundleTransactionCallback.java",
         "com/mysdk/IListFloatTransactionCallback.java",
         "com/mysdk/IListCharTransactionCallback.java",
         "com/mysdk/IListIntTransactionCallback.java",
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/input/com/mysdk/TestSandboxSdk.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/input/com/mysdk/TestSandboxSdk.kt
index 75a5a09..cb9adaa 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/input/com/mysdk/TestSandboxSdk.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/input/com/mysdk/TestSandboxSdk.kt
@@ -1,5 +1,6 @@
 package com.mysdk
 
+import android.os.Bundle
 import androidx.privacysandbox.tools.PrivacySandboxService
 
 @PrivacySandboxService
@@ -24,6 +25,8 @@
 
     suspend fun doSomethingAsync(first: Int, second: String, third: Long): Boolean
 
+    suspend fun doSomethingWithBundlesAsync(first: Int, second: Bundle): Bundle
+
     suspend fun receiveAndReturnNothingAsync()
 
     suspend fun processIntList(x: List<Int>): List<Int>
@@ -42,5 +45,7 @@
 
     suspend fun processStringList(x: List<String>): List<String>
 
+    suspend fun processBundleList(x: List<Bundle>): List<Bundle>
+
     suspend fun processNullableInt(x: Int?): Int?
 }
\ No newline at end of file
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/output/com/mysdk/TestSandboxSdk.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/output/com/mysdk/TestSandboxSdk.kt
index cb65c54..2afad24 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/output/com/mysdk/TestSandboxSdk.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/output/com/mysdk/TestSandboxSdk.kt
@@ -1,5 +1,7 @@
 package com.mysdk
 
+import android.os.Bundle
+
 public interface TestSandboxSdk {
     public suspend fun doSomethingAsync(
         first: Int,
@@ -7,6 +9,8 @@
         third: Long,
     ): Boolean
 
+    public suspend fun doSomethingWithBundlesAsync(first: Int, second: Bundle): Bundle
+
     public fun echoBoolean(input: Boolean)
 
     public fun echoChar(input: Char)
@@ -23,6 +27,8 @@
 
     public suspend fun processBooleanList(x: List<Boolean>): List<Boolean>
 
+    public suspend fun processBundleList(x: List<Bundle>): List<Bundle>
+
     public suspend fun processCharList(x: List<Char>): List<Char>
 
     public suspend fun processDoubleList(x: List<Double>): List<Double>
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/output/com/mysdk/TestSandboxSdkClientProxy.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/output/com/mysdk/TestSandboxSdkClientProxy.kt
index bc02194..6c0b587 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/output/com/mysdk/TestSandboxSdkClientProxy.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/primitives/output/com/mysdk/TestSandboxSdkClientProxy.kt
@@ -1,5 +1,6 @@
 package com.mysdk
 
+import android.os.Bundle
 import com.mysdk.PrivacySandboxThrowableParcelConverter.fromThrowableParcel
 import kotlin.coroutines.resumeWithException
 import kotlinx.coroutines.suspendCancellableCoroutine
@@ -33,6 +34,29 @@
         }
     }
 
+    public override suspend fun doSomethingWithBundlesAsync(first: Int, second: Bundle): Bundle =
+            suspendCancellableCoroutine {
+        var mCancellationSignal: ICancellationSignal? = null
+        val transactionCallback = object: IBundleTransactionCallback.Stub() {
+            override fun onCancellable(cancellationSignal: ICancellationSignal) {
+                if (it.isCancelled) {
+                    cancellationSignal.cancel()
+                }
+                mCancellationSignal = cancellationSignal
+            }
+            override fun onSuccess(result: Bundle) {
+                it.resumeWith(Result.success(result))
+            }
+            override fun onFailure(throwableParcel: PrivacySandboxThrowableParcel) {
+                it.resumeWithException(fromThrowableParcel(throwableParcel))
+            }
+        }
+        remote.doSomethingWithBundlesAsync(first, second, transactionCallback)
+        it.invokeOnCancellation {
+            mCancellationSignal?.cancel()
+        }
+    }
+
     public override fun echoBoolean(input: Boolean) {
         remote.echoBoolean(input)
     }
@@ -84,6 +108,29 @@
         }
     }
 
+    public override suspend fun processBundleList(x: List<Bundle>): List<Bundle> =
+            suspendCancellableCoroutine {
+        var mCancellationSignal: ICancellationSignal? = null
+        val transactionCallback = object: IListBundleTransactionCallback.Stub() {
+            override fun onCancellable(cancellationSignal: ICancellationSignal) {
+                if (it.isCancelled) {
+                    cancellationSignal.cancel()
+                }
+                mCancellationSignal = cancellationSignal
+            }
+            override fun onSuccess(result: Array<Bundle>) {
+                it.resumeWith(Result.success(result.toList()))
+            }
+            override fun onFailure(throwableParcel: PrivacySandboxThrowableParcel) {
+                it.resumeWithException(fromThrowableParcel(throwableParcel))
+            }
+        }
+        remote.processBundleList(x.toTypedArray(), transactionCallback)
+        it.invokeOnCancellation {
+            mCancellationSignal?.cancel()
+        }
+    }
+
     public override suspend fun processCharList(x: List<Char>): List<Char> =
             suspendCancellableCoroutine {
         var mCancellationSignal: ICancellationSignal? = null
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/input/com/sdkwithvalues/SdkInterface.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/input/com/sdkwithvalues/SdkInterface.kt
index a38b76e..6359994 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/input/com/sdkwithvalues/SdkInterface.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/input/com/sdkwithvalues/SdkInterface.kt
@@ -1,5 +1,6 @@
 package com.sdkwithvalues
 
+import android.os.Bundle
 import androidx.privacysandbox.tools.PrivacySandboxInterface
 import androidx.privacysandbox.tools.PrivacySandboxService
 import androidx.privacysandbox.tools.PrivacySandboxValue
@@ -29,8 +30,10 @@
     val myInterface: MyInterface,
     val myUiInterface: MyUiInterface,
     val numbers: List<Int>,
+    val bundle: Bundle,
     val maybeNumber: Int?,
     val maybeInterface: MyInterface?,
+    val maybeBundle: Bundle?,
 )
 
 @PrivacySandboxValue
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/InnerSdkValue.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/InnerSdkValue.kt
index 392ac9e..b88cc6a 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/InnerSdkValue.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/InnerSdkValue.kt
@@ -1,5 +1,7 @@
 package com.sdkwithvalues
 
+import android.os.Bundle
+
 public data class InnerSdkValue(
     public val id: Int,
     public val bigLong: Long,
@@ -11,6 +13,8 @@
     public val myInterface: MyInterface,
     public val myUiInterface: MyUiInterface,
     public val numbers: List<Int>,
+    public val bundle: Bundle,
     public val maybeNumber: Int?,
     public val maybeInterface: MyInterface?,
+    public val maybeBundle: Bundle?,
 )
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/InnerSdkValueConverter.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/InnerSdkValueConverter.kt
index aa7cbf4..02315c4 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/InnerSdkValueConverter.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/values/output/com/sdkwithvalues/InnerSdkValueConverter.kt
@@ -14,9 +14,11 @@
                 myUiInterface = MyUiInterfaceClientProxy(parcelable.myUiInterface.binder,
                         parcelable.myUiInterface.coreLibInfo),
                 numbers = parcelable.numbers.toList(),
+                bundle = parcelable.bundle,
                 maybeNumber = parcelable.maybeNumber.firstOrNull(),
                 maybeInterface = parcelable.maybeInterface?.let { notNullValue ->
-                        MyInterfaceClientProxy(notNullValue) })
+                        MyInterfaceClientProxy(notNullValue) },
+                maybeBundle = parcelable.maybeBundle)
         return annotatedValue
     }
 
@@ -34,10 +36,12 @@
                 IMyUiInterfaceCoreLibInfoAndBinderWrapperConverter.toParcelable((annotatedValue.myUiInterface
                 as MyUiInterfaceClientProxy).coreLibInfo, annotatedValue.myUiInterface.remote)
         parcelable.numbers = annotatedValue.numbers.toIntArray()
+        parcelable.bundle = annotatedValue.bundle
         parcelable.maybeNumber = if (annotatedValue.maybeNumber == null) intArrayOf() else
                 intArrayOf(annotatedValue.maybeNumber)
         parcelable.maybeInterface = annotatedValue.maybeInterface?.let { notNullValue ->
                 (notNullValue as MyInterfaceClientProxy).remote }
+        parcelable.maybeBundle = annotatedValue.maybeBundle
         return parcelable
     }
 }
diff --git a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/AidlGenerator.kt b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/AidlGenerator.kt
index 0ef1d46..9bc7b98 100644
--- a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/AidlGenerator.kt
+++ b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/AidlGenerator.kt
@@ -286,6 +286,7 @@
             Short::class.qualifiedName -> primitive("int")
             Unit::class.qualifiedName -> primitive("void")
             List::class.qualifiedName -> getAidlTypeDeclaration(type.typeParameters[0]).listSpec()
+            Types.bundle.qualifiedName -> bundleAidlType
             Types.sdkActivityLauncher.qualifiedName -> bundleAidlType
             else -> throw IllegalArgumentException(
                 "Unsupported type conversion ${type.qualifiedName}"
diff --git a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/BinderCodeConverter.kt b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/BinderCodeConverter.kt
index fd91bd1..406e9c0 100644
--- a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/BinderCodeConverter.kt
+++ b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/BinderCodeConverter.kt
@@ -46,6 +46,10 @@
             if (Types.primitiveTypes.contains(type.asNonNull())) {
                 return CodeBlock.of("%L.firstOrNull()", expression)
             }
+            // AIDL and parcelables support Bundles as is, without transformation.
+            if (type.asNonNull() == Types.bundle) {
+                return CodeBlock.of(expression)
+            }
             return CodeBlock.of(
                 "%L?.let { notNullValue -> %L }",
                 expression,
@@ -113,6 +117,10 @@
                     expression
                 )
             }
+            // AIDL and parcelables support Bundles as is, without transformation.
+            if (nonNullType == Types.bundle) {
+                return CodeBlock.of(expression)
+            }
             return CodeBlock.of(
                 "%L?.let { notNullValue -> %L }",
                 expression,
diff --git a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/model/Models.kt b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/model/Models.kt
index 28c2c35..767b03d 100644
--- a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/model/Models.kt
+++ b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/model/Models.kt
@@ -67,6 +67,7 @@
     val primitiveTypes = setOf(unit, boolean, int, long, float, double, string, char, short)
 
     val any = Type("kotlin", simpleName = "Any")
+    val bundle = Type("android.os", "Bundle")
     val sandboxedUiAdapter =
         Type(packageName = "androidx.privacysandbox.ui.core", simpleName = "SandboxedUiAdapter")
     val sdkActivityLauncher = Type(
diff --git a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/validator/ModelValidator.kt b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/validator/ModelValidator.kt
index 20e573c..7074ebf 100644
--- a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/validator/ModelValidator.kt
+++ b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/validator/ModelValidator.kt
@@ -114,7 +114,9 @@
 
     private fun validateValuePropertyTypes() {
         for (value in api.values) {
-            if (value !is AnnotatedDataClass) { continue }
+            if (value !is AnnotatedDataClass) {
+                continue
+            }
             for (property in value.properties) {
                 if (!isValidValuePropertyType(property.type)) {
                     errors.add(
@@ -173,12 +175,26 @@
             if (type.isNullable) {
                 errors.add("Nullable lists are not supported")
             }
-            return type.typeParameters[0].let { isValue(it) || isPrimitive(it) }
+            val typeParameter = type.typeParameters.first()
+            if (typeParameter.isNullable) {
+                errors.add(
+                    "Nullable type parameters are not supported in lists, found ${
+                        typeParameter.qualifiedName
+                    }"
+                )
+            }
+            val holdsValidType =
+                isValue(typeParameter) || isPrimitive(typeParameter) || isBundledType(typeParameter)
+            if (!holdsValidType) {
+                errors.add("Invalid type parameter in list, found ${typeParameter.qualifiedName}.")
+            }
+            return true
         }
         return false
     }
 
-    private fun isBundledType(type: Type) = type == Types.sdkActivityLauncher
+    private fun isBundledType(type: Type) =
+        type == Types.sdkActivityLauncher || type.asNonNull() == Types.bundle
 }
 
 data class ValidationResult(val errors: List<String>) {
diff --git a/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/generator/AidlValueGeneratorTest.kt b/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/generator/AidlValueGeneratorTest.kt
index cf22612..b3e0805 100644
--- a/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/generator/AidlValueGeneratorTest.kt
+++ b/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/generator/AidlValueGeneratorTest.kt
@@ -48,7 +48,9 @@
                 ValueProperty("booleanProperty", Types.boolean),
                 ValueProperty("longProperty", Types.long),
                 ValueProperty("maybeFloatProperty", Types.float.asNullable()),
-                ValueProperty("enumProperty", innerEnum.type)
+                ValueProperty("enumProperty", innerEnum.type),
+                ValueProperty("bundleProperty", Types.bundle),
+                ValueProperty("maybeBundleProperty", Types.bundle.asNullable())
             )
         )
         val outerValue = AnnotatedDataClass(
diff --git a/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/validator/ModelValidatorTest.kt b/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/validator/ModelValidatorTest.kt
index fea53d4..c76a38a 100644
--- a/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/validator/ModelValidatorTest.kt
+++ b/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/validator/ModelValidatorTest.kt
@@ -328,10 +328,36 @@
         val validationResult = ModelValidator.validate(api)
         assertThat(validationResult.isFailure).isTrue()
         assertThat(validationResult.errors).containsExactly(
-            "Error in com.mysdk.MySdk.processNestedList: only primitives, lists, data classes " +
-                "annotated with @PrivacySandboxValue, interfaces annotated with " +
-                "@PrivacySandboxCallback or @PrivacySandboxInterface, and SdkActivityLaunchers " +
-                "are supported as parameter types."
+            "Invalid type parameter in list, found kotlin.collections.List."
+        )
+    }
+
+    @Test
+    fun listWithNullable_throws() {
+        val api = ParsedApi(
+            services = setOf(
+                AnnotatedInterface(
+                    type = Type(packageName = "com.mysdk", simpleName = "MySdk"),
+                    methods = listOf(
+                        Method(
+                            name = "processNestedList",
+                            parameters = listOf(
+                                Parameter(
+                                    name = "foo",
+                                    type = Types.list(Types.int.asNullable())
+                                )
+                            ),
+                            returnType = Types.unit,
+                            isSuspend = true,
+                        ),
+                    ),
+                ),
+            )
+        )
+        val validationResult = ModelValidator.validate(api)
+        assertThat(validationResult.isFailure).isTrue()
+        assertThat(validationResult.errors).containsExactly(
+            "Nullable type parameters are not supported in lists, found kotlin.Int"
         )
     }
 
diff --git a/privacysandbox/tools/tools-core/src/test/test-data/aidlvaluegeneratortest/output/com/mysdk/ParcelableInnerValue.aidl b/privacysandbox/tools/tools-core/src/test/test-data/aidlvaluegeneratortest/output/com/mysdk/ParcelableInnerValue.aidl
index cf49d62..8381a53 100644
--- a/privacysandbox/tools/tools-core/src/test/test-data/aidlvaluegeneratortest/output/com/mysdk/ParcelableInnerValue.aidl
+++ b/privacysandbox/tools/tools-core/src/test/test-data/aidlvaluegeneratortest/output/com/mysdk/ParcelableInnerValue.aidl
@@ -1,8 +1,11 @@
 package com.mysdk;
 
+import android.os.Bundle;
 import com.mysdk.ParcelableInnerEnum;
 
 parcelable ParcelableInnerValue {
+    Bundle bundleProperty;
+    Bundle maybeBundleProperty;
     ParcelableInnerEnum enumProperty;
     boolean booleanProperty;
     float[] maybeFloatProperty;