Merge "Expose a list of default values for XAnnotation" into androidx-main
diff --git a/appactions/interaction/interaction-capabilities-core/lint-baseline.xml b/appactions/interaction/interaction-capabilities-core/lint-baseline.xml
deleted file mode 100644
index 845b3c4..0000000
--- a/appactions/interaction/interaction-capabilities-core/lint-baseline.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues name="AGP (8.1.0-beta02)" by="lint 8.1.0-beta02" client="gradle" dependencies="false"
-    format="6" type="baseline" variant="all" version="8.1.0-beta02">
-
-    <!-- Need to use reflection to dynamically access serializers based on type-name. These
-    serializers may be coming from a downstream artifact and are not available at compile-time.
-    This also aids in a binary-bloat optimization where all serializers start off a dead code and
-    then we instruct proguard to only retain the serializers for types that are explicitly
-    referenced and prune others.
-    -->
-    <issue
-        errorLine1="                .map { it.invoke(null) as BuiltInTypeSerializer&lt;*> }"
-        errorLine2="                       ~~~~~~~~~~~~~~~"
-        id="BanUncheckedReflection"
-        message="Calling `Method.invoke` without an SDK check">
-        <location
-            file="src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt" />
-    </issue>
-
-</issues>
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt
index 0d0d278..f80c2f3 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt
@@ -52,6 +52,7 @@
  *   [BuiltInTypeSerializer].
  * @param getClassOrNull Functor that returns a class ref given its canonical name, or null.
  */
+@Suppress("BanUncheckedReflection")
 class BuiltInTypeSerializerRegistry(
     serializerRegistryClassNames: List<String>,
     getClassOrNull: (canonicalName: String) -> Class<*>?
@@ -61,6 +62,11 @@
         Collections.synchronizedMap(mutableMapOf())
 
     init {
+        // Need to use reflection to dynamically access serializers based on type-name. These
+        // serializers may be coming from a downstream artifact and are not available at
+        // compile-time. This also aids in a binary-bloat optimization where all serializers start
+        // off a dead code and then we instruct proguard to only retain the serializers for types
+        // that are explicitly referenced and prune others.
         val serializers =
             serializerRegistryClassNames
                 // object AllProductivitySerializers
diff --git a/appsearch/appsearch/api/current.txt b/appsearch/appsearch/api/current.txt
index 6724a679..96049d0 100644
--- a/appsearch/appsearch/api/current.txt
+++ b/appsearch/appsearch/api/current.txt
@@ -31,12 +31,6 @@
   @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DoubleProperty {
     method public abstract String name() default "";
     method public abstract boolean required() default false;
-    method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.DoubleProperty.DefaultSerializer.class;
-  }
-
-  public static final class Document.DoubleProperty.DefaultSerializer {
-    method public static double deserialize(double);
-    method public static double serialize(double);
   }
 
   @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Id {
@@ -46,12 +40,13 @@
     method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_NONE;
     method public abstract String name() default "";
     method public abstract boolean required() default false;
-    method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.LongProperty.DefaultSerializer.class;
+    method public abstract Class<? extends androidx.appsearch.app.LongSerializer<?>> serializer() default androidx.appsearch.annotation.Document.LongProperty.DefaultSerializer.class;
   }
 
-  public static final class Document.LongProperty.DefaultSerializer {
-    method public static long deserialize(long);
-    method public static long serialize(long);
+  public static final class Document.LongProperty.DefaultSerializer implements androidx.appsearch.app.LongSerializer<java.lang.Long> {
+    ctor public Document.LongProperty.DefaultSerializer();
+    method public Long deserialize(long);
+    method public long serialize(Long);
   }
 
   @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Namespace {
@@ -65,13 +60,14 @@
     method public abstract int joinableValueType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE;
     method public abstract String name() default "";
     method public abstract boolean required() default false;
-    method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.StringProperty.DefaultSerializer.class;
+    method public abstract Class<? extends androidx.appsearch.app.StringSerializer<?>> serializer() default androidx.appsearch.annotation.Document.StringProperty.DefaultSerializer.class;
     method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
   }
 
-  public static final class Document.StringProperty.DefaultSerializer {
-    method public static String deserialize(String);
-    method public static String serialize(String);
+  public static final class Document.StringProperty.DefaultSerializer implements androidx.appsearch.app.StringSerializer<java.lang.String> {
+    ctor public Document.StringProperty.DefaultSerializer();
+    method public String deserialize(String);
+    method public String serialize(String);
   }
 
   @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.TtlMillis {
@@ -380,6 +376,11 @@
     method public androidx.appsearch.app.JoinSpec.Builder setNestedSearch(String, androidx.appsearch.app.SearchSpec);
   }
 
+  public interface LongSerializer<T> {
+    method public T? deserialize(long);
+    method public long serialize(T);
+  }
+
   public abstract class Migrator {
     ctor public Migrator();
     method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onDowngrade(int, int, androidx.appsearch.app.GenericDocument);
@@ -701,6 +702,11 @@
     method public androidx.appsearch.app.StorageInfo.Builder setSizeBytes(long);
   }
 
+  public interface StringSerializer<T> {
+    method public T? deserialize(String);
+    method public String serialize(T);
+  }
+
 }
 
 package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/api/restricted_current.txt b/appsearch/appsearch/api/restricted_current.txt
index 6724a679..96049d0 100644
--- a/appsearch/appsearch/api/restricted_current.txt
+++ b/appsearch/appsearch/api/restricted_current.txt
@@ -31,12 +31,6 @@
   @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DoubleProperty {
     method public abstract String name() default "";
     method public abstract boolean required() default false;
-    method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.DoubleProperty.DefaultSerializer.class;
-  }
-
-  public static final class Document.DoubleProperty.DefaultSerializer {
-    method public static double deserialize(double);
-    method public static double serialize(double);
   }
 
   @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Id {
@@ -46,12 +40,13 @@
     method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_NONE;
     method public abstract String name() default "";
     method public abstract boolean required() default false;
-    method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.LongProperty.DefaultSerializer.class;
+    method public abstract Class<? extends androidx.appsearch.app.LongSerializer<?>> serializer() default androidx.appsearch.annotation.Document.LongProperty.DefaultSerializer.class;
   }
 
-  public static final class Document.LongProperty.DefaultSerializer {
-    method public static long deserialize(long);
-    method public static long serialize(long);
+  public static final class Document.LongProperty.DefaultSerializer implements androidx.appsearch.app.LongSerializer<java.lang.Long> {
+    ctor public Document.LongProperty.DefaultSerializer();
+    method public Long deserialize(long);
+    method public long serialize(Long);
   }
 
   @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Namespace {
@@ -65,13 +60,14 @@
     method public abstract int joinableValueType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE;
     method public abstract String name() default "";
     method public abstract boolean required() default false;
-    method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.StringProperty.DefaultSerializer.class;
+    method public abstract Class<? extends androidx.appsearch.app.StringSerializer<?>> serializer() default androidx.appsearch.annotation.Document.StringProperty.DefaultSerializer.class;
     method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
   }
 
-  public static final class Document.StringProperty.DefaultSerializer {
-    method public static String deserialize(String);
-    method public static String serialize(String);
+  public static final class Document.StringProperty.DefaultSerializer implements androidx.appsearch.app.StringSerializer<java.lang.String> {
+    ctor public Document.StringProperty.DefaultSerializer();
+    method public String deserialize(String);
+    method public String serialize(String);
   }
 
   @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.TtlMillis {
@@ -380,6 +376,11 @@
     method public androidx.appsearch.app.JoinSpec.Builder setNestedSearch(String, androidx.appsearch.app.SearchSpec);
   }
 
+  public interface LongSerializer<T> {
+    method public T? deserialize(long);
+    method public long serialize(T);
+  }
+
   public abstract class Migrator {
     ctor public Migrator();
     method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onDowngrade(int, int, androidx.appsearch.app.GenericDocument);
@@ -701,6 +702,11 @@
     method public androidx.appsearch.app.StorageInfo.Builder setSizeBytes(long);
   }
 
+  public interface StringSerializer<T> {
+    method public T? deserialize(String);
+    method public String serialize(T);
+  }
+
 }
 
 package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
index e1a3fcb..6b09339 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
@@ -18,6 +18,8 @@
 
 import androidx.annotation.NonNull;
 import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.LongSerializer;
+import androidx.appsearch.app.StringSerializer;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
@@ -259,18 +261,7 @@
          * <p>Useful for representing properties using rich types that boil down to simple string
          * values in the database.
          *
-         * <p>The referenced class must satisfy the following:
-         *
-         * <ol>
-         *     <li>
-         *         Have a static method called {@code serialize} that converts the property's Java
-         *         type to a {@link String}.
-         *     </li>
-         *     <li>
-         *         Have a static method called {@code deserialize} that converts a {@link String} to
-         *         the property's Java type or returns null if deserialization failed.
-         *     </li>
-         * </ol>
+         * <p>The referenced class must have a public zero params constructor.
          *
          * <p>For example:
          *
@@ -282,17 +273,21 @@
          *     @Document.StringProperty(serializer = SomeRichTypeSerializer.class)
          *     public SomeRichType getMyProperty();
          *
-         *     public final class SomeRichTypeSerializer {
-         *       public static String serialize(SomeRichType instance) {...}
+         *     public final class SomeRichTypeSerializer implements StringSerializer<SomeRichType> {
          *
+         *       @Override
+         *       @NonNull
+         *       public String serialize(@NonNull SomeRichType instance) {...}
+         *
+         *       @Override
          *       @Nullable
-         *       public static SomeRichType deserialize(String string) {...}
+         *       public SomeRichType deserialize(@NonNull String string) {...}
          *     }
          * }
          * }
          * </pre>
          */
-        Class<?> serializer() default DefaultSerializer.class;
+        Class<? extends StringSerializer<?>> serializer() default DefaultSerializer.class;
 
         /**
          * Configures whether this property must be specified for the document to be valid.
@@ -305,16 +300,16 @@
          */
         boolean required() default false;
 
-        final class DefaultSerializer {
-            private DefaultSerializer() {}
-
+        final class DefaultSerializer implements StringSerializer<String> {
+            @Override
             @NonNull
-            public static String serialize(@NonNull String value) {
-                return value;
+            public String serialize(@NonNull String instance) {
+                return instance;
             }
 
+            @Override
             @NonNull
-            public static String deserialize(@NonNull String string) {
+            public String deserialize(@NonNull String string) {
                 return string;
             }
         }
@@ -387,22 +382,11 @@
          * <p>Useful for representing properties using rich types that boil down to simple 64-bit
          * integer values in the database.
          *
-         * <p>The referenced class must satisfy the following:
-         *
-         * <ol>
-         *     <li>
-         *         Have a static method called {@code serialize} that converts the property's Java
-         *         type to a {@link Long}.
-         *     </li>
-         *     <li>
-         *         Have a static method called {@code deserialize} that converts a {@link Long} to
-         *         the property's Java type or returns null if deserialization failed.
-         *     </li>
-         * </ol>
+         * <p>The referenced class must have a public zero params constructor.
          *
          * <p>See {@link StringProperty#serializer()} for an example of a serializer.
          */
-        Class<?> serializer() default DefaultSerializer.class;
+        Class<? extends LongSerializer<?>> serializer() default DefaultSerializer.class;
 
         /**
          * Configures whether this property must be specified for the document to be valid.
@@ -415,15 +399,17 @@
          */
         boolean required() default false;
 
-        final class DefaultSerializer {
-            private DefaultSerializer() {}
-
-            public static long serialize(long value) {
+        final class DefaultSerializer implements LongSerializer<Long> {
+            @Override
+            public long serialize(@NonNull @SuppressWarnings("AutoBoxing") Long value) {
                 return value;
             }
 
-            public static long deserialize(long l) {
-                return l;
+            @Override
+            @NonNull
+            @SuppressWarnings("AutoBoxing")
+            public Long deserialize(long value) {
+                return value;
             }
         }
     }
@@ -444,29 +430,6 @@
         String name() default "";
 
         /**
-         * Configures how a property should be converted to and from a {@link Double}.
-         *
-         * <p>Useful for representing properties using rich types that boil down to simple
-         * double-precision decimal values in the database.
-         *
-         * <p>The referenced class must satisfy the following:
-         *
-         * <ol>
-         *     <li>
-         *         Have a static method called {@code serialize} that converts the property's Java
-         *         type to a {@link Double}.
-         *     </li>
-         *     <li>
-         *         Have a static method called {@code deserialize} that converts a {@link Double} to
-         *         the property's Java type or returns null if deserialization failed.
-         *     </li>
-         * </ol>
-         *
-         * <p>See {@link StringProperty#serializer()} for an example of a serializer.
-         */
-        Class<?> serializer() default DefaultSerializer.class;
-
-        /**
          * Configures whether this property must be specified for the document to be valid.
          *
          * <p>This attribute does not apply to properties of a repeated type (e.g. a list).
@@ -476,18 +439,6 @@
          * this attribute to {@code true}.
          */
         boolean required() default false;
-
-        final class DefaultSerializer {
-            private DefaultSerializer() {}
-
-            public static double serialize(double value) {
-                return value;
-            }
-
-            public static double deserialize(double d) {
-                return d;
-            }
-        }
     }
 
     /** Configures a boolean member field of a class as a property known to AppSearch. */
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/LongSerializer.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/LongSerializer.java
new file mode 100644
index 0000000..7c597bc
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/LongSerializer.java
@@ -0,0 +1,38 @@
+/*
+ * 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.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Serializes some {@link T} to and from a long.
+ *
+ * @param <T> The custom type that can be serialized to a long.
+ */
+public interface LongSerializer<T> {
+    /**
+     * Serializes a {@link T} to a long.
+     */
+    long serialize(@NonNull T instance);
+
+    /**
+     * Deserializes a {@link T} from a long. Returns null if deserialization failed.
+     */
+    @Nullable
+    T deserialize(long value);
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/StringSerializer.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/StringSerializer.java
new file mode 100644
index 0000000..bdfa575
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/StringSerializer.java
@@ -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.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Serializes some {@link T} to and from a String.
+ *
+ * @param <T> The custom type that can be serialized to a String.
+ */
+public interface StringSerializer<T> {
+    /**
+     * Serializes a {@link T} to a String.
+     */
+    @NonNull
+    String serialize(@NonNull T instance);
+
+    /**
+     * Deserializes a {@link T} from a String. Returns null if deserialization failed.
+     */
+    @Nullable
+    T deserialize(@NonNull String string);
+}
diff --git a/appsearch/compiler/build.gradle b/appsearch/compiler/build.gradle
index cb9caf4..c37b877 100644
--- a/appsearch/compiler/build.gradle
+++ b/appsearch/compiler/build.gradle
@@ -31,6 +31,8 @@
     implementation(libs.autoValueAnnotations)
     implementation(libs.javapoet)
 
+    annotationProcessor(libs.autoValue)
+
     // For testing, add in the compiled classes from appsearch to get access to annotations.
     testImplementationAarAsJar(project(":appsearch:appsearch"))
     testImplementation(libs.googleCompileTesting)
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
index ad2e92e..bc30992 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
@@ -20,7 +20,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
-import androidx.annotation.VisibleForTesting;
 
 import com.google.auto.value.AutoValue;
 import com.squareup.javapoet.ClassName;
@@ -57,18 +56,18 @@
  * @exportToFramework:hide
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-class IntrospectionHelper {
-    @VisibleForTesting
+public class IntrospectionHelper {
     static final String GEN_CLASS_PREFIX = "$$__AppSearch__";
     static final String APPSEARCH_PKG = "androidx.appsearch.app";
     static final String APPSEARCH_EXCEPTION_PKG = "androidx.appsearch.exceptions";
     static final String APPSEARCH_EXCEPTION_SIMPLE_NAME = "AppSearchException";
-    static final String DOCUMENT_ANNOTATION_CLASS = "androidx.appsearch.annotation.Document";
+    public static final String DOCUMENT_ANNOTATION_CLASS = "androidx.appsearch.annotation.Document";
     static final String ID_CLASS = "androidx.appsearch.annotation.Document.Id";
     static final String NAMESPACE_CLASS = "androidx.appsearch.annotation.Document.Namespace";
     static final String CREATION_TIMESTAMP_MILLIS_CLASS =
             "androidx.appsearch.annotation.Document.CreationTimestampMillis";
-    static final String TTL_MILLIS_CLASS = "androidx.appsearch.annotation.Document.TtlMillis";
+    static final String TTL_MILLIS_CLASS = "androidx.appsearch.annotation.Document"
+            + ".TtlMillis";
     static final String SCORE_CLASS = "androidx.appsearch.annotation.Document.Score";
     static final String BUILDER_PRODUCER_CLASS =
             "androidx.appsearch.annotation.Document.BuilderProducer";
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BooleanPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BooleanPropertyAnnotation.java
new file mode 100644
index 0000000..0d84e17
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BooleanPropertyAnnotation.java
@@ -0,0 +1,50 @@
+/*
+ * 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.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.BooleanProperty} annotation.
+ */
+@AutoValue
+public abstract class BooleanPropertyAnnotation extends DataPropertyAnnotation {
+    public static final String SIMPLE_CLASS_NAME = "BooleanProperty";
+    public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+    public BooleanPropertyAnnotation() {
+        super(SIMPLE_CLASS_NAME);
+    }
+
+    /**
+     * @param defaultName The name to use for the annotated property in case the annotation
+     *                    params do not mention an explicit name.
+     */
+    @NonNull
+    static BooleanPropertyAnnotation parse(
+            @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+        String name = (String) annotationParams.get("name");
+        return new AutoValue_BooleanPropertyAnnotation(
+                name.isEmpty() ? defaultName : name, (boolean) annotationParams.get("required"));
+    }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BytesPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BytesPropertyAnnotation.java
new file mode 100644
index 0000000..35cc428
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BytesPropertyAnnotation.java
@@ -0,0 +1,50 @@
+/*
+ * 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.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.BytesProperty} annotation.
+ */
+@AutoValue
+public abstract class BytesPropertyAnnotation extends DataPropertyAnnotation {
+    public static final String SIMPLE_CLASS_NAME = "BytesProperty";
+    public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+    public BytesPropertyAnnotation() {
+        super(SIMPLE_CLASS_NAME);
+    }
+
+    /**
+     * @param defaultName The name to use for the annotated property in case the annotation
+     *                    params do not mention an explicit name.
+     */
+    @NonNull
+    static BytesPropertyAnnotation parse(
+            @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+        String name = (String) annotationParams.get("name");
+        return new AutoValue_BytesPropertyAnnotation(
+                name.isEmpty() ? defaultName : name, (boolean) annotationParams.get("required"));
+    }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DataPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DataPropertyAnnotation.java
new file mode 100644
index 0000000..245072a
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DataPropertyAnnotation.java
@@ -0,0 +1,95 @@
+/*
+ * 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.appsearch.compiler.annotationwrapper;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appsearch.compiler.IntrospectionHelper;
+
+import java.util.Map;
+
+import javax.lang.model.element.AnnotationMirror;
+
+/**
+ * An instance of an annotation for a data property e.g. {@code @Document.StringProperty}.
+ *
+ * <p>Is one of:
+ * <ul>
+ *     <li>{@link StringPropertyAnnotation}</li>
+ *     <li>{@link DocumentPropertyAnnotation}</li>
+ *     <li>{@link LongPropertyAnnotation}</li>
+ *     <li>{@link DoublePropertyAnnotation}</li>
+ *     <li>{@link BooleanPropertyAnnotation}</li>
+ *     <li>{@link BytesPropertyAnnotation}</li>
+ * </ul>
+ */
+public abstract class DataPropertyAnnotation implements PropertyAnnotation {
+    @NonNull
+    private final String mSimpleClassName;
+
+    DataPropertyAnnotation(@NonNull String simpleClassName) {
+        mSimpleClassName = simpleClassName;
+    }
+
+    /**
+     * Attempts to parse an {@link AnnotationMirror} into a {@link DataPropertyAnnotation}, or null.
+     *
+     * @param defaultName The name to use for the annotated property in case the annotation
+     *                    params do not mention an explicit name.
+     */
+    @Nullable
+    public static DataPropertyAnnotation tryParse(
+            @NonNull AnnotationMirror annotation,
+            @NonNull String defaultName,
+            @NonNull IntrospectionHelper helper) {
+        Map<String, Object> annotationParams = helper.getAnnotationParams(annotation);
+        String qualifiedClassName = annotation.getAnnotationType().toString();
+        switch (qualifiedClassName) {
+            case BooleanPropertyAnnotation.CLASS_NAME:
+                return BooleanPropertyAnnotation.parse(annotationParams, defaultName);
+            case BytesPropertyAnnotation.CLASS_NAME:
+                return BytesPropertyAnnotation.parse(annotationParams, defaultName);
+            case DocumentPropertyAnnotation.CLASS_NAME:
+                return DocumentPropertyAnnotation.parse(annotationParams, defaultName);
+            case DoublePropertyAnnotation.CLASS_NAME:
+                return DoublePropertyAnnotation.parse(annotationParams, defaultName);
+            case LongPropertyAnnotation.CLASS_NAME:
+                return LongPropertyAnnotation.parse(annotationParams, defaultName);
+            case StringPropertyAnnotation.CLASS_NAME:
+                return StringPropertyAnnotation.parse(annotationParams, defaultName);
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * The serialized name for the property in the database.
+     */
+    @NonNull
+    public abstract String getName();
+
+    /**
+     * Denotes whether this property must be specified for the document to be valid.
+     */
+    public abstract boolean isRequired();
+
+    @NonNull
+    @Override
+    public final String getSimpleClassName() {
+        return mSimpleClassName;
+    }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DocumentPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DocumentPropertyAnnotation.java
new file mode 100644
index 0000000..53c2523
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DocumentPropertyAnnotation.java
@@ -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.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.DocumentProperty} annotation.
+ */
+@AutoValue
+public abstract class DocumentPropertyAnnotation extends DataPropertyAnnotation {
+    public static final String SIMPLE_CLASS_NAME = "DocumentProperty";
+    public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+    public DocumentPropertyAnnotation() {
+        super(SIMPLE_CLASS_NAME);
+    }
+
+    /**
+     * @param defaultName The name to use for the annotated property in case the annotation
+     *                    params do not mention an explicit name.
+     */
+    @NonNull
+    static DocumentPropertyAnnotation parse(
+            @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+        String name = (String) annotationParams.get("name");
+        return new AutoValue_DocumentPropertyAnnotation(
+                name.isEmpty() ? defaultName : name,
+                (boolean) annotationParams.get("required"),
+                (boolean) annotationParams.get("indexNestedProperties"));
+    }
+
+    /**
+     * Specifies whether fields in the nested document should be indexed.
+     */
+    public abstract boolean shouldIndexNestedProperties();
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DoublePropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DoublePropertyAnnotation.java
new file mode 100644
index 0000000..1a85e16
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DoublePropertyAnnotation.java
@@ -0,0 +1,50 @@
+/*
+ * 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.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.DoubleProperty} annotation.
+ */
+@AutoValue
+public abstract class DoublePropertyAnnotation extends DataPropertyAnnotation {
+    public static final String SIMPLE_CLASS_NAME = "DoubleProperty";
+    public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+    public DoublePropertyAnnotation() {
+        super(SIMPLE_CLASS_NAME);
+    }
+
+    /**
+     * @param defaultName The name to use for the annotated property in case the annotation
+     *                    params do not mention an explicit name.
+     */
+    @NonNull
+    static DoublePropertyAnnotation parse(
+            @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+        String name = (String) annotationParams.get("name");
+        return new AutoValue_DoublePropertyAnnotation(
+                name.isEmpty() ? defaultName : name, (boolean) annotationParams.get("required"));
+    }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/LongPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/LongPropertyAnnotation.java
new file mode 100644
index 0000000..2f66b04
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/LongPropertyAnnotation.java
@@ -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.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.LongProperty} annotation.
+ */
+@AutoValue
+public abstract class LongPropertyAnnotation extends DataPropertyAnnotation {
+    public static final String SIMPLE_CLASS_NAME = "LongProperty";
+    public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+    public LongPropertyAnnotation() {
+        super(SIMPLE_CLASS_NAME);
+    }
+
+    /**
+     * @param defaultName The name to use for the annotated property in case the annotation
+     *                    params do not mention an explicit name.
+     */
+    @NonNull
+    static LongPropertyAnnotation parse(
+            @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+        String name = (String) annotationParams.get("name");
+        return new AutoValue_LongPropertyAnnotation(
+                name.isEmpty() ? defaultName : name,
+                (boolean) annotationParams.get("required"),
+                (int) annotationParams.get("indexingType"));
+    }
+
+    /**
+     * Specifies how a property should be indexed.
+     */
+    public abstract int getIndexingType();
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/MetadataPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/MetadataPropertyAnnotation.java
new file mode 100644
index 0000000..9253048
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/MetadataPropertyAnnotation.java
@@ -0,0 +1,64 @@
+/*
+ * 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.appsearch.compiler.annotationwrapper;
+
+import static java.util.Objects.requireNonNull;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Arrays;
+
+import javax.lang.model.element.AnnotationMirror;
+
+/**
+ * An annotation for a metadata property e.g. {@code @Document.Id}.
+ */
+public enum MetadataPropertyAnnotation implements PropertyAnnotation {
+    ID(/* simpleClassName= */"Id"),
+    NAMESPACE(/* simpleClassName= */"Namespace"),
+    CREATION_TIMESTAMP_MILLIS(/* simpleClassName= */"CreationTimestampMillis"),
+    TTL_MILLIS(/* simpleClassName= */"TtlMillis"),
+    SCORE(/* simpleClassName= */"Score");
+
+    /**
+     * Attempts to parse an {@link AnnotationMirror} into a {@link MetadataPropertyAnnotation},
+     * or null.
+     */
+    @Nullable
+    public static MetadataPropertyAnnotation tryParse(@NonNull AnnotationMirror annotation) {
+        String qualifiedClassName = annotation.getAnnotationType().toString();
+        return Arrays.stream(values())
+                .filter(val -> val.getQualifiedClassName().equals(qualifiedClassName))
+                .findFirst()
+                .orElse(null);
+    }
+
+    @NonNull
+    private final String mSimpleClassName;
+
+    MetadataPropertyAnnotation(@NonNull String simpleClassName) {
+        mSimpleClassName = requireNonNull(simpleClassName);
+    }
+
+    @Override
+    @NonNull
+    public String getSimpleClassName() {
+        return mSimpleClassName;
+    }
+}
+
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/PropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/PropertyAnnotation.java
new file mode 100644
index 0000000..41cf474
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/PropertyAnnotation.java
@@ -0,0 +1,51 @@
+/*
+ * 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.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+/**
+ * An instance of an AppSearch property annotation.
+ *
+ * <p>Is one of:
+ * <ul>
+ *     <li>{@link MetadataPropertyAnnotation} e.g. {@code  @Document.Id}</li>
+ *     <li>{@link DataPropertyAnnotation} e.g. {@code @Document.StringProperty}</li>
+ * </ul>
+ */
+public interface PropertyAnnotation {
+    /**
+     * The annotation class' simple name.
+     *
+     * <p>For example, {@code StringProperty} for a {@link StringPropertyAnnotation}.
+     */
+    @NonNull
+    String getSimpleClassName();
+
+    /**
+     * The annotation class' qualified name
+     *
+     * <p>{@code androidx.appsearch.annotation.Document.StringProperty} for a
+     * {@link StringPropertyAnnotation}.
+     */
+    @NonNull
+    default String getQualifiedClassName() {
+        return DOCUMENT_ANNOTATION_CLASS + "." + getSimpleClassName();
+    }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/StringPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/StringPropertyAnnotation.java
new file mode 100644
index 0000000..ddcdf8e
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/StringPropertyAnnotation.java
@@ -0,0 +1,69 @@
+/*
+ * 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.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.StringProperty} annotation.
+ */
+@AutoValue
+public abstract class StringPropertyAnnotation extends DataPropertyAnnotation {
+    public static final String SIMPLE_CLASS_NAME = "StringProperty";
+    public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+    public StringPropertyAnnotation() {
+        super(SIMPLE_CLASS_NAME);
+    }
+
+    /**
+     * @param defaultName The name to use for the annotated property in case the annotation
+     *                    params do not mention an explicit name.
+     */
+    @NonNull
+    static StringPropertyAnnotation parse(
+            @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+        String name = (String) annotationParams.get("name");
+        return new AutoValue_StringPropertyAnnotation(
+                name.isEmpty() ? defaultName : name,
+                (boolean) annotationParams.get("required"),
+                (int) annotationParams.get("tokenizerType"),
+                (int) annotationParams.get("indexingType"),
+                (int) annotationParams.get("joinableValueType"));
+    }
+
+    /**
+     * Specifies how tokens should be extracted from this property.
+     */
+    public abstract int getTokenizerType();
+
+    /**
+     * Specifies how a property should be indexed.
+     */
+    public abstract int getIndexingType();
+
+    /**
+     * Specifies how a property should be processed so that the document can be joined.
+     */
+    public abstract int getJoinableValueType();
+}
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/InMemoryTracingTest.kt
similarity index 84%
rename from benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt
rename to benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/InMemoryTracingTest.kt
index 20f264f..ad72a77 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/InMemoryTracingTest.kt
@@ -16,6 +16,7 @@
 
 package androidx.benchmark
 
+import android.os.Process
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
@@ -23,35 +24,29 @@
 import kotlin.test.assertNotNull
 import org.junit.After
 import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import perfetto.protos.ThreadDescriptor
 import perfetto.protos.TracePacket
 import perfetto.protos.TrackDescriptor
 import perfetto.protos.TrackEvent
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
-class UserspaceTracingTest {
+class InMemoryTracingTest {
     @Before
     @After
     fun setup() {
-        UserspaceTracing.commitToTrace() // reset
+        InMemoryTracing.clearEvents() // reset
     }
 
     @Test
     fun emptyTrace() {
-        val beforeTime = System.nanoTime()
-        UserspaceTracing.commitToTrace() // reset, and trigger first event in next trace
-        val afterTime = System.nanoTime()
-
-        val trace = UserspaceTracing.commitToTrace() // capture trace
+        val trace = InMemoryTracing.commitToTrace("testLabel") // capture trace
 
         assertEquals(1, trace.packet.size)
         val packet = trace.packet.first()
-
-        assertTrue(packet.timestamp in beforeTime..afterTime)
         assertEquals(
             packet,
             TracePacket(
@@ -60,7 +55,9 @@
                 incremental_state_cleared = true,
                 track_descriptor = TrackDescriptor(
                     uuid = packet.track_descriptor?.uuid,
-                    name = "Macrobenchmark"
+                    name = "testLabel",
+                    thread = ThreadDescriptor(pid = Process.myPid(), tid = Process.myTid()),
+                    disallow_merging_with_system_tracks = true
                 )
             )
         )
@@ -69,16 +66,19 @@
     @Test
     fun minimalTrace() {
         val beforeTime = System.nanoTime()
-        userspaceTrace("test trace section") {}
+        inMemoryTrace("test trace section") {}
         val afterTime = System.nanoTime()
 
-        val trace = UserspaceTracing.commitToTrace()
+        val trace = InMemoryTracing.commitToTrace("testLabel")
 
         assertEquals(3, trace.packet.size)
 
+        // verify track
         val descriptor = trace.packet.first().track_descriptor
-        assertNotNull(descriptor) // verify track
+        assertNotNull(descriptor)
+        assertEquals("testLabel", descriptor.name)
 
+        // verify events
         trace.packet[1].apply {
             assert(timestamp in beforeTime..afterTime)
             assertEquals(
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
index b6ab1fc..6df6bcd 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
@@ -250,7 +250,7 @@
 
         if (phaseIndex >= 0) {
             currentPhase.profiler?.stop()
-            UserspaceTracing.endSection()
+            InMemoryTracing.endSection()
             thermalThrottleSleepSeconds += currentPhase.thermalThrottleSleepSeconds
             if (currentPhase.loopMode.warmupManager == null && currentPhase.profiler == null) {
                 // Always save metrics, except during warmup / profiling
@@ -282,7 +282,7 @@
 
         iterationsPerRepeat = iterationsPerRepeat.coerceAtLeast(currentLoopsPerMeasurement)
 
-        UserspaceTracing.beginSection(currentPhase.label)
+        InMemoryTracing.beginSection(currentPhase.label)
         val phaseProfilerResult = currentPhase.profiler?.start(traceUniqueName)
         if (phaseProfilerResult != null) {
             require(profilerResult == null) {
@@ -385,7 +385,7 @@
         if (!value) {
             ThreadPriority.resetBumpedThread()
             if (phaseIndex >= 0 && phaseIndex <= phases.size) {
-                UserspaceTracing.endSection() // current phase cancelled, complete trace event
+                InMemoryTracing.endSection() // current phase cancelled, complete trace event
             }
             throw IllegalStateException(lazyMessage())
         }
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/InMemoryTracing.kt
similarity index 67%
rename from benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
rename to benchmark/benchmark-common/src/main/java/androidx/benchmark/InMemoryTracing.kt
index 5972a77..4b171eb 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/InMemoryTracing.kt
@@ -16,25 +16,32 @@
 
 package androidx.benchmark
 
+import android.os.Process
 import androidx.annotation.RestrictTo
+import androidx.benchmark.InMemoryTracing.commitToTrace
+import perfetto.protos.ThreadDescriptor
 import perfetto.protos.Trace
 import perfetto.protos.TracePacket
 import perfetto.protos.TrackDescriptor
 import perfetto.protos.TrackEvent
 
 /**
- * Userspace-buffer-based tracing api, that provides implementation for [userspaceTrace].
+ * Tracing api that writes events directly into memory.
  *
- * This records while atrace isn't capturing by storing trace events manually in a list of
- * in-userspace-memory perfetto protos.
+ * This has a few advantages over typical atrace:
+ * - can record while atrace isn't captured either due to platform limitations (old platforms may
+ *   only allow one process to be traced at a time), or when debugging benchmark performance, it can
+ *   capture when atrace isn't active (e.g. tracing the start/stop of perfetto)
+ * - can create events asynchronously, deferring record cost (e.g. micro creating events after all
+ *   measurements, using existing timestamps)
+ * - can customize presentation of events in trace
  *
  * After trace processing, the extra events (before _and_ after the measureBlock section of a
  * benchmark) can be added to the trace by calling [commitToTrace], and appending that to the
  * trace on-disk.
- *
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-object UserspaceTracing {
+object InMemoryTracing {
     /**
      * All events emitted by the benchmark annotation should have the same value.
      * the value needs to not conflict with any sequence id emitted in the trace.
@@ -58,39 +65,44 @@
     private const val CLOCK_ID = 3
 
     /**
-     * Name of track in for userspace tracing events
-     */
-    private const val TRACK_DESCRIPTOR_NAME = "Macrobenchmark"
-
-    /**
      * Tag to enable post-filtering of events in the trace.
      */
     private val TRACK_EVENT_CATEGORIES = listOf("benchmark")
 
-    private fun createInitialTracePacket() = TracePacket(
-        timestamp = System.nanoTime(),
-        timestamp_clock_id = CLOCK_ID,
-        incremental_state_cleared = true,
-        track_descriptor = TrackDescriptor(
-            uuid = UUID,
-            name = TRACK_DESCRIPTOR_NAME
-        )
-    )
-
     /**
      * For perf/simplicity, this isn't protected by a lock - it should only every be
      * accessed by the test thread, and dumped/reset between tests.
      */
-    val events = mutableListOf(createInitialTracePacket())
+    val events = mutableListOf<TracePacket>()
+
+    fun clearEvents() {
+        events.clear()
+    }
 
     /**
      * Capture trace state, and return as a Trace(), which can be appended to a trace file.
      */
-    fun commitToTrace(): Trace {
+    fun commitToTrace(
+        label: String
+    ): Trace {
         val capturedEvents = events.toList()
-        events.clear()
-        events.add(createInitialTracePacket())
-        return Trace(capturedEvents)
+        clearEvents()
+        return Trace(
+            listOf(
+                TracePacket(
+                    timestamp_clock_id = CLOCK_ID,
+                    incremental_state_cleared = true,
+                    track_descriptor = TrackDescriptor(
+                        uuid = UUID,
+                        name = label,
+                        thread = ThreadDescriptor(pid = Process.myPid(), tid = Process.myTid()),
+                        // currently separate for clarity, to allow InMemoryTrace events to have a visible
+                        // track name, but not override the thread name
+                        disallow_merging_with_system_tracks = true
+                    )
+                )
+            ) + capturedEvents
+        )
     }
 
     fun beginSection(label: String, nanoTime: Long = System.nanoTime()) {
@@ -125,11 +137,11 @@
 }
 
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-inline fun <T> userspaceTrace(label: String, block: () -> T): T {
-    UserspaceTracing.beginSection(label)
+inline fun <T> inMemoryTrace(label: String, block: () -> T): T {
+    InMemoryTracing.beginSection(label)
     return try {
         block()
     } finally {
-        UserspaceTracing.endSection()
+        InMemoryTracing.endSection()
     }
 }
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt
index 50e30ad..d0ae847 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt
@@ -54,7 +54,7 @@
     internal val data: List<LongArray> = List(repeatCount) { LongArray(names.size) }
 
     /**
-     * Array of start / stop time, per measurement, to be passed to [UserspaceTracing].
+     * Array of start / stop time, per measurement, to be passed to [InMemoryTracing].
      *
      * These values are used both in metric calculation and trace data, so tracing is extremely low
      * overhead - just the cost of storing the timing data in an additional place in memory.
@@ -135,8 +135,8 @@
      */
     fun captureFinished(maxIterations: Int): List<MetricResult> {
         for (i in 0..repeatTiming.lastIndex step 2) {
-            UserspaceTracing.beginSection("measurement ${i / 2}", nanoTime = repeatTiming[i])
-            UserspaceTracing.endSection(nanoTime = repeatTiming[i + 1])
+            InMemoryTracing.beginSection("measurement ${i / 2}", nanoTime = repeatTiming[i])
+            InMemoryTracing.endSection(nanoTime = repeatTiming[i + 1])
         }
 
         return names.mapIndexed { index, name ->
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkPhase.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkPhase.kt
index e8cba451..a21e9c8 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkPhase.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkPhase.kt
@@ -53,7 +53,7 @@
                 "THERMAL THROTTLE DETECTED, SLEEPING FOR $THROTTLE_BACKOFF_S SECONDS"
             )
             val startTimeNs = System.nanoTime()
-            userspaceTrace("Sleep due to Thermal Throttle") {
+            inMemoryTrace("Sleep due to Thermal Throttle") {
                 Thread.sleep(TimeUnit.SECONDS.toMillis(THROTTLE_BACKOFF_S))
             }
             val sleepTimeNs = System.nanoTime() - startTimeNs
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/RunListenerDelegate.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/RunListenerDelegate.kt
new file mode 100644
index 0000000..b9332af
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/RunListenerDelegate.kt
@@ -0,0 +1,55 @@
+/*
+ * 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.benchmark
+
+import android.util.Log
+import androidx.annotation.RestrictTo
+
+/**
+ * Actions that need to be performed once per test suite are defined in this [RunListenerDelegate].
+ *
+ * This way, we minimize the costs of these suite wide actions, and benchmarks continue running
+ * fast (with minimal additional overheads).
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class RunListenerDelegate(private val sideEffects: List<SideEffect>) {
+    /**
+     * Called before any tests have been run.
+     */
+    fun onTestRunStarted() {
+        sideEffects.forEach { sideEffect ->
+            Log.d(
+                BenchmarkState.TAG,
+                "Setting up side effect ${sideEffect.name()}"
+            )
+            sideEffect.setup()
+        }
+    }
+
+    /**
+     * Called after all tests have been completed.
+     */
+    fun onTestRunFinished() {
+        sideEffects.forEach { sideEffect ->
+            Log.d(
+                BenchmarkState.TAG,
+                "Tearing down side effect ${sideEffect.name()}"
+            )
+            sideEffect.tearDown()
+        }
+    }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
index faabcf9..6811685 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
@@ -588,7 +588,7 @@
             if (runningProcesses.isEmpty()) {
                 return
             }
-            userspaceTrace("wait for $runningProcesses to die") {
+            inMemoryTrace("wait for $runningProcesses to die") {
                 SystemClock.sleep(waitPollPeriodMs)
             }
             Log.d(BenchmarkState.TAG, "Waiting $waitPollPeriodMs ms for $runningProcesses to die")
@@ -611,6 +611,34 @@
     }
 
     @RequiresApi(21)
+    fun disablePackages(appPackages: List<String>) {
+        val command = appPackages.joinToString(separator = "\n") { appPackage ->
+            "pm disable-user $appPackage"
+        }
+        executeScriptCaptureStdoutStderr(command)
+    }
+
+    @RequiresApi(21)
+    fun enablePackages(appPackages: List<String>) {
+        val command = appPackages.joinToString(separator = "\n") { appPackage ->
+            "pm enable $appPackage"
+        }
+        executeScriptCaptureStdoutStderr(command)
+    }
+
+    @RequiresApi(24)
+    fun disableBackgroundDexOpt() {
+        // Cancels the active job if any
+        ShellImpl.executeCommandUnsafe("cmd package bg-dexopt-job --cancel")
+        ShellImpl.executeCommandUnsafe("cmd package bg-dexopt-job --disable")
+    }
+
+    @RequiresApi(24)
+    fun enableBackgroundDexOpt() {
+        ShellImpl.executeCommandUnsafe("cmd package bg-dexopt-job --enable")
+    }
+
+    @RequiresApi(21)
     fun isSELinuxEnforced(): Boolean {
         return when (val value = executeScriptCaptureStdout("getenforce").trim()) {
             "Permissive" -> false
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffect.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffect.kt
new file mode 100644
index 0000000..512851d
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffect.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.benchmark
+
+import androidx.annotation.RestrictTo
+
+/**
+* Represents actions that effect changes to the state of the app / device outside of the scope
+* of the benchmark. Typically used to help reduce the amount of interference during a benchmark.
+*
+* [SideEffect]s must define a [setup], that is executed when the benchmark starts. The [tearDown]
+* method is called during the end of the benchmark to reverse actions so subsequent invocations of
+* the benchmark are hermetic.
+*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+interface SideEffect {
+
+    /**
+     * Returns the canonical name of the [SideEffect].
+     */
+    fun name(): String
+
+    /**
+     * This method is executed when the benchmark starts.
+     */
+    fun setup()
+
+    /**
+     * This method is executed when the benchmark is complete. A [SideEffect] should undo
+     * the changes to the state of the device app, to ensure hermetic benchmarks.
+     */
+    fun tearDown()
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffects.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffects.kt
new file mode 100644
index 0000000..c520311
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffects.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.benchmark
+
+import android.os.Build
+import android.util.Log
+import androidx.annotation.RestrictTo
+
+/**
+ * Disables the [packages] during the course of a benchmark thereby reducing the amount of noise.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class DisablePackages(
+    private val packages: List<String> = DEFAULT_PACKAGES_TO_DISABLE
+) : SideEffect {
+    override fun name(): String {
+        return "DisablePackages"
+    }
+
+    override fun setup() {
+        if (Build.VERSION.SDK_INT >= 21) {
+            Log.d(BenchmarkState.TAG, "Disabling packages $packages")
+            Shell.disablePackages(packages)
+        }
+    }
+
+    override fun tearDown() {
+        if (Build.VERSION.SDK_INT >= 21) {
+            Log.d(BenchmarkState.TAG, "Re-enabling packages $packages")
+            Shell.enablePackages(packages)
+        }
+    }
+
+    companion object {
+        // A list of packages to disable + "com.google.android.gms"
+        // https://source.corp.google.com/piper///depot/google3/java/com/google/android/libraries/swpower/fixture/DisableModule.java
+        internal val DEFAULT_PACKAGES_TO_DISABLE = listOf(
+            "com.android.chrome",
+            "com.android.phone",
+            "com.android.ramdump",
+            "com.android.vending",
+            "com.google.android.apps.docs",
+            "com.google.android.apps.gcs",
+            "com.google.android.apps.internal.betterbug",
+            "com.google.android.apps.maps",
+            "com.google.android.apps.messaging",
+            "com.google.android.apps.nbu.files",
+            "com.google.android.apps.photos",
+            "com.google.android.apps.scone",
+            "com.google.android.apps.tips",
+            "com.google.android.apps.turbo",
+            "com.google.android.apps.tycho",
+            "com.google.android.apps.work.clouddpc",
+            "com.google.android.apps.youtube.music",
+            "com.google.android.as",
+            "com.google.android.calculator",
+            "com.google.android.calendar",
+            "com.google.android.configupdater",
+            "com.google.android.contacts",
+            "com.google.android.deskclock",
+            "com.google.android.dialer",
+            "com.google.android.googlequicksearchbox",
+            "com.google.android.gm",
+            "com.google.android.gms",
+            "com.google.android.GoogleCamera",
+            "com.google.android.ims",
+            "com.google.android.inputmethod.latin",
+            "com.google.android.marvin.talkback",
+            "com.google.android.partnersetup",
+            "com.google.android.settings.intelligence",
+            "com.google.android.tts",
+            "com.google.android.videos",
+            "com.google.android.youtube",
+            "com.google.android.videos",
+            "com.google.android.volta"
+        )
+    }
+}
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class DisableDexOpt : SideEffect {
+    override fun name(): String {
+        return "DisableDexOpt"
+    }
+
+    override fun setup() {
+        // PGO was enabled on Android N
+        if (Build.VERSION.SDK_INT >= 24) {
+            Shell.disableBackgroundDexOpt()
+        }
+    }
+
+    override fun tearDown() {
+        if (Build.VERSION.SDK_INT >= 24) {
+            Shell.enableBackgroundDexOpt()
+        }
+    }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
index 8cd40a0..2f5a387 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
@@ -22,9 +22,9 @@
 import androidx.annotation.RestrictTo
 import androidx.benchmark.Outputs
 import androidx.benchmark.Shell
+import androidx.benchmark.inMemoryTrace
 import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig.InitialProcessState
 import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
-import androidx.benchmark.userspaceTrace
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.tracing.perfetto.handshake.PerfettoSdkHandshake
 import androidx.tracing.perfetto.handshake.protocol.ResponseResultCodes.RESULT_CODE_ALREADY_ENABLED
@@ -57,18 +57,18 @@
     /**
      * Start collecting perfetto trace.
      */
-    fun start(config: PerfettoConfig) = userspaceTrace("start perfetto") {
+    fun start(config: PerfettoConfig) = inMemoryTrace("start perfetto") {
         // Write config proto to dir that shell can read
         //     We use `.pb` even with textproto so we'll only ever have one file
         val configProtoFile = File(Outputs.dirUsableByAppAndShell, "trace_config.pb")
         try {
-            userspaceTrace("write config") {
+            inMemoryTrace("write config") {
                 config.writeTo(configProtoFile)
                 if (Outputs.forceFilesForShellAccessible) {
                     configProtoFile.setReadable(true, /* ownerOnly = */ false)
                 }
             }
-            userspaceTrace("start perfetto process") {
+            inMemoryTrace("start perfetto process") {
                 helper.startCollecting(configProtoFile.absolutePath, config.isTextProto)
             }
         } finally {
@@ -82,7 +82,7 @@
      * @param destinationPath Absolute path to write perfetto trace to. Must be shell-writable,
      * such as result of `context.getExternalFilesDir(null)` or other similar `external` paths.
      */
-    public fun stop(destinationPath: String) = userspaceTrace("stop perfetto") {
+    public fun stop(destinationPath: String) = inMemoryTrace("stop perfetto") {
         helper.stopCollecting(destinationPath)
     }
 
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
index 278416e..c823e02 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
@@ -20,12 +20,14 @@
 import android.util.Log
 import androidx.annotation.RequiresApi
 import androidx.annotation.RestrictTo
+import androidx.benchmark.InMemoryTracing
 import androidx.benchmark.Outputs
 import androidx.benchmark.Outputs.dateToFileName
 import androidx.benchmark.PropOverride
 import androidx.benchmark.Shell
 import androidx.benchmark.perfetto.PerfettoHelper.Companion.LOG_TAG
 import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
+import java.io.File
 
 /**
  * Wrapper for [PerfettoCapture] which does nothing below API 23.
@@ -93,6 +95,7 @@
         perfettoSdkConfig: PerfettoCapture.PerfettoSdkConfig?,
         traceCallback: ((String) -> Unit)? = null,
         enableTracing: Boolean = true,
+        inMemoryTracingLabel: String? = null,
         block: () -> Unit
     ): String? {
         // skip if Perfetto not supported, or if caller opts out
@@ -122,11 +125,20 @@
         try {
             propOverride?.forceValue()
             start(config, perfettoSdkConfig)
+
+            // To avoid b/174007010, userspace tracing is cleared and saved *during* trace, so
+            // that events won't lie outside the bounds of the trace content.
+            InMemoryTracing.clearEvents()
             try {
                 block()
             } finally {
                 // finally here to ensure trace is fully recorded if block throws
                 path = stop(fileLabel)
+
+                if (inMemoryTracingLabel != null) {
+                    val inMemoryTrace = InMemoryTracing.commitToTrace(inMemoryTracingLabel)
+                    File(path).appendBytes(inMemoryTrace.encode())
+                }
                 traceCallback?.invoke(path)
             }
             return path
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
index 2491c74..b4fdbc1 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
@@ -23,8 +23,8 @@
 import androidx.annotation.RestrictTo
 import androidx.benchmark.DeviceInfo.deviceSummaryString
 import androidx.benchmark.Shell
+import androidx.benchmark.inMemoryTrace
 import androidx.benchmark.perfetto.PerfettoHelper.Companion.MIN_SDK_VERSION
-import androidx.benchmark.userspaceTrace
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.tracing.trace
 import java.io.File
@@ -165,7 +165,7 @@
      * This is a good indicator that tracing is actually enabled (including the app atrace tag), and
      * that content will be captured in the trace buffer
      */
-    private fun checkTracingOn(): Unit = userspaceTrace("poll tracing_on") {
+    private fun checkTracingOn(): Unit = inMemoryTrace("poll tracing_on") {
         val path: String = when {
             Shell.pathExists(TRACING_ON_PATH) -> {
                 TRACING_ON_PATH
@@ -187,7 +187,7 @@
         repeat(pollTracingOnMaxCount) {
             when (val output = Shell.executeScriptCaptureStdout("cat $path").trim()) {
                 "0" -> {
-                    userspaceTrace("wait for trace to start (tracing_on == 1)") {
+                    inMemoryTrace("wait for trace to start (tracing_on == 1)") {
                         SystemClock.sleep(pollTracingOnMs)
                     }
                 }
@@ -232,12 +232,12 @@
         // Stop the perfetto and copy the output file.
         Log.i(LOG_TAG, "Stopping perfetto.")
 
-        userspaceTrace("stop perfetto process") {
+        inMemoryTrace("stop perfetto process") {
             stopPerfetto()
         }
 
         Log.i(LOG_TAG, "Writing to $destinationFile.")
-        userspaceTrace("copy trace to output dir") {
+        inMemoryTrace("copy trace to output dir") {
             copyFileOutput(destinationFile)
         }
     }
@@ -410,7 +410,7 @@
         }
 
         fun createExecutable(tool: String): String {
-            userspaceTrace("create executable: $tool") {
+            inMemoryTrace("create executable: $tool") {
                 if (!isAbiSupported()) {
                     throw IllegalStateException(
                         "Unsupported ABI (${Build.SUPPORTED_ABIS.joinToString()})"
diff --git a/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt
index 5fcf6977..c39aaf8 100644
--- a/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt
+++ b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt
@@ -25,7 +25,6 @@
 import androidx.benchmark.DeviceInfo
 import androidx.benchmark.ExperimentalBenchmarkConfigApi
 import androidx.benchmark.MicrobenchmarkConfig
-import androidx.benchmark.UserspaceTracing
 import androidx.benchmark.perfetto.PerfettoCapture
 import androidx.benchmark.perfetto.PerfettoCaptureWrapper
 import androidx.benchmark.perfetto.PerfettoConfig
@@ -217,8 +216,6 @@
             val uniqueName = description.testClass.simpleName + "_" + invokeMethodName
             internalState.traceUniqueName = uniqueName
 
-            var userspaceTrace: perfetto.protos.Trace? = null
-
             val tracePath = PerfettoCaptureWrapper().record(
                 fileLabel = uniqueName,
                 config = PerfettoConfig.Benchmark(
@@ -245,19 +242,13 @@
                 // Optimize throughput in dryRunMode, since trace isn't useful, and extremely
                 //   expensive on some emulators. Could alternately use UserspaceTracing if desired
                 // Additionally, skip on misconfigured devices to still enable benchmarking.
-                enableTracing = !Arguments.dryRunMode && !DeviceInfo.misconfiguredForTracing
+                enableTracing = !Arguments.dryRunMode && !DeviceInfo.misconfiguredForTracing,
+                inMemoryTracingLabel = "Microbenchmark"
             ) {
-                UserspaceTracing.commitToTrace() // clear buffer
-
                 trace(description.displayName) { base.evaluate() }
-
-                // To avoid b/174007010, userspace tracing is cleared and saved *during* trace, so
-                // that events won't lie outside the bounds of the trace content.
-                userspaceTrace = UserspaceTracing.commitToTrace()
             }?.apply {
                 // trace completed, and copied into shell writeable dir
                 val file = File(this)
-                file.appendBytes(userspaceTrace!!.encode())
                 file.appendUiState(
                     UiState(
                         timelineStart = null,
diff --git a/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/SideEffectRunListener.kt b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/SideEffectRunListener.kt
new file mode 100644
index 0000000..fa14e63
--- /dev/null
+++ b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/SideEffectRunListener.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.benchmark.junit4
+
+import androidx.annotation.RestrictTo
+import androidx.benchmark.DisableDexOpt
+import androidx.benchmark.DisablePackages
+import androidx.benchmark.RunListenerDelegate
+import org.junit.runner.Description
+import org.junit.runner.Result
+import org.junit.runner.notification.RunListener
+
+/**
+ * Enables the use of side-effects that reduce the noise during a benchmark run.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class SideEffectRunListener : RunListener() {
+    private val delegate: RunListenerDelegate = RunListenerDelegate(
+        sideEffects = listOf(
+            DisablePackages(),
+            DisableDexOpt(),
+        )
+    )
+
+    override fun testRunStarted(description: Description) {
+        super.testRunStarted(description)
+        delegate.onTestRunStarted()
+    }
+
+    override fun testRunFinished(result: Result) {
+        super.testRunFinished(result)
+        delegate.onTestRunFinished()
+    }
+}
diff --git a/benchmark/benchmark-macro/api/1.2.0-beta02.txt b/benchmark/benchmark-macro/api/1.2.0-beta02.txt
index 6b770f4..54c8a8c 100644
--- a/benchmark/benchmark-macro/api/1.2.0-beta02.txt
+++ b/benchmark/benchmark-macro/api/1.2.0-beta02.txt
@@ -208,7 +208,7 @@
   }
 
   @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
-    ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode);
+    ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
   }
 
   public enum TraceSectionMetric.Mode {
diff --git a/benchmark/benchmark-macro/api/current.txt b/benchmark/benchmark-macro/api/current.txt
index 6b770f4..54c8a8c 100644
--- a/benchmark/benchmark-macro/api/current.txt
+++ b/benchmark/benchmark-macro/api/current.txt
@@ -208,7 +208,7 @@
   }
 
   @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
-    ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode);
+    ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
   }
 
   public enum TraceSectionMetric.Mode {
diff --git a/benchmark/benchmark-macro/api/restricted_1.2.0-beta02.txt b/benchmark/benchmark-macro/api/restricted_1.2.0-beta02.txt
index 32628f3..9fb21fd 100644
--- a/benchmark/benchmark-macro/api/restricted_1.2.0-beta02.txt
+++ b/benchmark/benchmark-macro/api/restricted_1.2.0-beta02.txt
@@ -230,7 +230,7 @@
   }
 
   @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
-    ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode);
+    ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
   }
 
   public enum TraceSectionMetric.Mode {
diff --git a/benchmark/benchmark-macro/api/restricted_current.txt b/benchmark/benchmark-macro/api/restricted_current.txt
index 32628f3..9fb21fd 100644
--- a/benchmark/benchmark-macro/api/restricted_current.txt
+++ b/benchmark/benchmark-macro/api/restricted_current.txt
@@ -230,7 +230,7 @@
   }
 
   @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
-    ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode);
+    ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
   }
 
   public enum TraceSectionMetric.Mode {
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
index 03de19f..09a6c7d 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
@@ -96,7 +96,8 @@
             className = "MacrobenchmarkTest",
             testName = "validateCallbackBehavior",
             packageName = Packages.TARGET,
-            metrics = listOf(TraceSectionMetric(TRACE_LABEL)),
+            // disable targetPackageOnly filter, since this process emits the event
+            metrics = listOf(TraceSectionMetric(TRACE_LABEL, targetPackageOnly = false)),
             compilationMode = CompilationMode.DEFAULT,
             iterations = 2,
             startupMode = startupMode,
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/PerfettoTraceRuleTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/PerfettoTraceRuleTest.kt
index b8b2819..d5229ca 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/PerfettoTraceRuleTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/PerfettoTraceRuleTest.kt
@@ -58,7 +58,7 @@
                     val sliceNameInstances = PerfettoTraceProcessor.runSingleSessionServer(
                         trace!!.path
                     ) {
-                        querySlices(UNIQUE_SLICE_NAME)
+                        querySlices(UNIQUE_SLICE_NAME, packageName = null)
                             .map { slice -> slice.name }
                     }
                     assertEquals(listOf(UNIQUE_SLICE_NAME), sliceNameInstances)
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt
index 4eedd27..d69c472 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt
@@ -38,7 +38,7 @@
     @Test
     fun activityThreadMain() = verifyFirstSum(
         tracePath = api24ColdStart,
-        packageName = Packages.TEST,
+        packageName = Packages.TARGET,
         sectionName = "ActivityThreadMain",
         expectedFirstMs = 12.639
     )
@@ -46,7 +46,7 @@
     @Test
     fun activityStart() = verifyFirstSum(
         tracePath = api24ColdStart,
-        packageName = Packages.TEST,
+        packageName = Packages.TARGET,
         sectionName = "activityStart",
         expectedFirstMs = 81.979
     )
@@ -54,17 +54,18 @@
     @Test
     fun startActivityAndWait() = verifyFirstSum(
         tracePath = api24ColdStart,
-        packageName = Packages.TEST,
+        packageName = "androidx.benchmark.integration.macrobenchmark.test",
         sectionName = "startActivityAndWait",
-        expectedFirstMs = 1_110.689
+        expectedFirstMs = 1_110.689,
     )
 
     @Test
     fun launching() = verifyFirstSum(
         tracePath = api24ColdStart,
-        packageName = Packages.TEST,
+        packageName = Packages.TARGET,
         sectionName = "launching: androidx.benchmark.integration.macrobenchmark.target",
-        expectedFirstMs = 269.947
+        expectedFirstMs = 269.947,
+        targetPackageOnly = false // slice from system_server
     )
 
     @Test
@@ -76,23 +77,28 @@
     )
 
     @Test
-    fun multiSection() = verifyFirstSum(
+    fun multiSection_targetOnly() = verifyFirstSum(
+        tracePath = api24ColdStart,
+        packageName = Packages.TARGET,
+        sectionName = "inflate",
+        expectedFirstMs = 4.949, // first inflation
+        expectedSumMs = 19.779, // total inflation
+        expectedSumCount = 3,
+        targetPackageOnly = true,
+    )
+
+    @Test
+    fun multiSection_unfiltered() = verifyFirstSum(
         tracePath = api24ColdStart,
         packageName = Packages.TARGET,
         sectionName = "inflate",
         expectedFirstMs = 13.318, // first inflation
         expectedSumMs = 43.128, // total inflation
         expectedSumCount = 8,
+        targetPackageOnly = false,
     )
 
     companion object {
-        private val captureInfo = Metric.CaptureInfo(
-            targetPackageName = Packages.TEST,
-            testPackageName = Packages.TEST,
-            startupMode = StartupMode.COLD,
-            apiLevel = 24
-        )
-
         private fun verifyMetric(
             tracePath: String,
             packageName: String,
@@ -100,15 +106,23 @@
             mode: TraceSectionMetric.Mode,
             expectedMs: Double,
             expectedCount: Int,
+            targetPackageOnly: Boolean
         ) {
             assumeTrue(PerfettoHelper.isAbiSupported())
 
-            val metric = TraceSectionMetric(sectionName, mode)
+            val metric = TraceSectionMetric(sectionName, mode, targetPackageOnly)
             metric.configure(packageName = packageName)
 
             val result = PerfettoTraceProcessor.runSingleSessionServer(tracePath) {
                 metric.getResult(
-                    captureInfo = captureInfo,
+                    // note that most args are incorrect here, but currently
+                    // only targetPackageName matters in this context
+                    captureInfo = Metric.CaptureInfo(
+                        targetPackageName = packageName,
+                        testPackageName = Packages.TEST,
+                        startupMode = StartupMode.COLD,
+                        apiLevel = 24
+                    ),
                     traceSession = this
                 )
             }
@@ -134,7 +148,8 @@
             sectionName: String,
             expectedFirstMs: Double,
             expectedSumMs: Double = expectedFirstMs, // default implies only one matching section
-            expectedSumCount: Int = 1
+            expectedSumCount: Int = 1,
+            targetPackageOnly: Boolean = true,
         ) {
             verifyMetric(
                 tracePath = tracePath,
@@ -142,7 +157,8 @@
                 sectionName = sectionName,
                 mode = TraceSectionMetric.Mode.First,
                 expectedMs = expectedFirstMs,
-                expectedCount = 1
+                expectedCount = 1,
+                targetPackageOnly = targetPackageOnly,
             )
             verifyMetric(
                 tracePath = tracePath,
@@ -151,6 +167,7 @@
                 mode = TraceSectionMetric.Mode.Sum,
                 expectedMs = expectedSumMs,
                 expectedCount = expectedSumCount,
+                targetPackageOnly = targetPackageOnly,
             )
         }
     }
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/BatteryDischargeQueryTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/BatteryDischargeQueryTest.kt
index db3bea2..31de56f 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/BatteryDischargeQueryTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/BatteryDischargeQueryTest.kt
@@ -42,7 +42,8 @@
         val traceFile = createTempFileFromAsset("api31_battery_discharge", ".perfetto-trace")
 
         val actualMetrics = PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
-            val slice = querySlices(PowerMetric.MEASURE_BLOCK_SECTION_NAME).first()
+            val slice =
+                querySlices(PowerMetric.MEASURE_BLOCK_SECTION_NAME, packageName = null).first()
             BatteryDischargeQuery.getBatteryDischargeMetrics(this, slice)
         }
 
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt
index 117726f..41d9868 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt
@@ -129,7 +129,7 @@
         perfettoCapture.stop(traceFilePath)
 
         val matchingSlices = PerfettoTraceProcessor.runSingleSessionServer(traceFilePath) {
-            querySlices("PerfettoCaptureTest_%")
+            querySlices("PerfettoCaptureTest_%", packageName = null)
         }
 
         // Note: this test avoids validating platform-triggered trace sections, to avoid flakes
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
index f8cbebb..0bcb3b4 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
@@ -43,7 +43,6 @@
 import org.junit.After
 import org.junit.Assume.assumeTrue
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -216,14 +215,10 @@
         }
     }
 
-    // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
-    @Ignore
     @Test
     fun test_handshake_framework_cold_start_persistent() =
         test_handshake_framework_cold_start(persistent = true)
 
-    // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
-    @Ignore
     @Test
     fun test_handshake_framework_cold_start_non_persistent() =
         test_handshake_framework_cold_start(persistent = false)
@@ -277,8 +272,6 @@
         }
     }
 
-    // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
-    @Ignore
     /**
      * Tests [androidx.benchmark.perfetto.PerfettoCapture.enableAndroidxTracingPerfetto] as
      * opposed to [androidx.tracing.perfetto.handshake.PerfettoSdkHandshake.enableTracingColdStart]
@@ -326,14 +319,10 @@
         }
     }
 
-    // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
-    @Ignore
     @Test
     fun test_handshake_framework_cold_start_disable_persistent() =
         test_handshake_framework_cold_start_disable(persistent = true)
 
-    // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
-    @Ignore
     @Test
     fun test_handshake_framework_cold_start_disable_non_persistent() =
         test_handshake_framework_cold_start_disable(persistent = true)
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkTraceTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkTraceTest.kt
index 07c1416..d171aaa 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkTraceTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkTraceTest.kt
@@ -58,7 +58,12 @@
             if (enableUserspaceTracing) yield(StringSource.userspaceTraceStrings)
         }.flatMap { it }.toList()
         val actualSlices = PerfettoTraceProcessor.runSingleSessionServer(trace.path) {
-            StringSource.allTraceStrings.flatMap { querySlices(it).map { s -> s.name } }
+            StringSource.allTraceStrings.flatMap {
+                querySlices(
+                    it,
+                    packageName = null
+                ).map { s -> s.name }
+            }
         }
         assertThat(actualSlices).containsExactlyElementsIn(expectedSlices)
     }
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PowerQueryTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PowerQueryTest.kt
index c3e4847..4c5e491 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PowerQueryTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PowerQueryTest.kt
@@ -43,7 +43,7 @@
         val actualMetrics = PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
             PowerQuery.getPowerMetrics(
                 this,
-                querySlices(MEASURE_BLOCK_SECTION_NAME).first()
+                querySlices(MEASURE_BLOCK_SECTION_NAME, packageName = null).first()
             )
         }
 
@@ -182,7 +182,10 @@
         val traceFile = createTempFileFromAsset("api31_odpm_rails_empty", ".perfetto-trace")
 
         val actualMetrics = PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
-            PowerQuery.getPowerMetrics(this, querySlices(MEASURE_BLOCK_SECTION_NAME).first())
+            PowerQuery.getPowerMetrics(
+                this,
+                querySlices(MEASURE_BLOCK_SECTION_NAME, packageName = null).first()
+            )
         }
 
         assertEquals(emptyMap(), actualMetrics)
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt
index e772ff9..37769a6 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt
@@ -21,7 +21,8 @@
 import androidx.benchmark.macro.createTempFileFromAsset
 import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
 import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
+import androidx.test.filters.LargeTest
+import androidx.test.filters.MediumTest
 import androidx.test.platform.app.InstrumentationRegistry
 import java.io.File
 import java.net.ConnectException
@@ -37,7 +38,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-@SmallTest
+@MediumTest
 @RunWith(AndroidJUnit4::class)
 class PerfettoTraceProcessorTest {
     @Test
@@ -93,38 +94,66 @@
         }
     }
 
+    enum class QuerySlicesMode(val target: String?) {
+        ValidPackage("androidx.benchmark.integration.macrobenchmark.target"),
+        Unspecified(null),
+        InvalidPackage("not.a.real.package")
+    }
+
     @Test
-    fun querySlices() {
+    fun querySlices_validPackage() = validateQuerySlices(QuerySlicesMode.ValidPackage)
+
+    @Test
+    fun querySlices_invalidPackage() = validateQuerySlices(QuerySlicesMode.InvalidPackage)
+
+    @Test
+    fun querySlices_unspecified() = validateQuerySlices(QuerySlicesMode.Unspecified)
+
+    private fun validateQuerySlices(mode: QuerySlicesMode) {
         // check known slice content is queryable
         assumeTrue(isAbiSupported())
         val traceFile = createTempFileFromAsset("api31_startup_cold", ".perfetto-trace")
         PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
             assertEquals(
-                expected = listOf(
-                    Slice(
-                        name = "activityStart",
-                        ts = 186975009436431,
-                        dur = 29580628
+                expected = when (mode) {
+                    QuerySlicesMode.InvalidPackage -> emptyList()
+                    else -> listOf(
+                        Slice(
+                            name = "activityStart",
+                            ts = 186975009436431,
+                            dur = 29580628
+                        )
                     )
-                ),
-                actual = querySlices("activityStart")
+                },
+                actual = querySlices("activityStart", packageName = mode.target)
             )
             assertEquals(
-                expected = listOf(
-                    Slice(
-                        name = "activityStart",
-                        ts = 186975009436431,
-                        dur = 29580628
-                    ),
-                    Slice(
-                        name = "activityResume",
-                        ts = 186975039764298,
-                        dur = 6570418
+                expected = when (mode) {
+                    QuerySlicesMode.InvalidPackage -> emptyList()
+                    else -> listOf(
+                        Slice(
+                            name = "activityStart",
+                            ts = 186975009436431,
+                            dur = 29580628
+                        ),
+                        Slice(
+                            name = "activityResume",
+                            ts = 186975039764298,
+                            dur = 6570418
+                        )
                     )
-                ),
-                actual = querySlices("activityStart", "activityResume")
+                },
+                actual = querySlices("activityStart", "activityResume", packageName = mode.target)
                     .sortedBy { it.ts }
             )
+            assertEquals(
+                expected = when (mode) {
+                    QuerySlicesMode.ValidPackage -> 7
+                    QuerySlicesMode.Unspecified -> 127
+                    QuerySlicesMode.InvalidPackage -> 0
+                },
+                actual = querySlices("Lock contention %", packageName = mode.target).size
+            )
         }
     }
 
@@ -253,6 +282,7 @@
         assertTrue(!isRunning())
     }
 
+    @LargeTest
     @Test
     fun parseLongTrace() {
         val traceFile = File
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
index cc75044..bb55014 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
@@ -27,7 +27,7 @@
 import androidx.benchmark.InstrumentationResults
 import androidx.benchmark.Outputs
 import androidx.benchmark.Shell
-import androidx.benchmark.userspaceTrace
+import androidx.benchmark.inMemoryTrace
 import java.io.File
 
 /**
@@ -59,7 +59,7 @@
         val finalMaxIterations = if (Arguments.dryRunMode) 1 else maxIterations
 
         while (iteration <= finalMaxIterations) {
-            userspaceTrace("generate profile for $packageName ($iteration)") {
+            inMemoryTrace("generate profile for $packageName ($iteration)") {
                 val mode = CompilationMode.Partial(
                     baselineProfileMode = BaselineProfileMode.Disable,
                     warmupIterations = 1
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
index 1b9da10..4aecd9b 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
@@ -24,11 +24,11 @@
 import androidx.benchmark.Arguments
 import androidx.benchmark.DeviceInfo
 import androidx.benchmark.Shell
+import androidx.benchmark.inMemoryTrace
 import androidx.benchmark.macro.CompilationMode.Full
 import androidx.benchmark.macro.CompilationMode.Ignore
 import androidx.benchmark.macro.CompilationMode.None
 import androidx.benchmark.macro.CompilationMode.Partial
-import androidx.benchmark.userspaceTrace
 import androidx.profileinstaller.ProfileInstallReceiver
 import org.junit.AssumptionViolatedException
 
@@ -123,7 +123,7 @@
      * does work on older APIs without root
      */
     private fun reinstallPackage(packageName: String) {
-        userspaceTrace("reinstallPackage") {
+        inMemoryTrace("reinstallPackage") {
 
             // Copy APKs to /data/local/temp
             val apkPaths = Shell.pmPath(packageName)
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
index c73d755..d1ad575 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
@@ -30,9 +30,9 @@
 import androidx.benchmark.Profiler
 import androidx.benchmark.ResultWriter
 import androidx.benchmark.Shell
-import androidx.benchmark.UserspaceTracing
 import androidx.benchmark.checkAndGetSuppressionState
 import androidx.benchmark.conditionalError
+import androidx.benchmark.inMemoryTrace
 import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig
 import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig.InitialProcessState
 import androidx.benchmark.perfetto.PerfettoCaptureWrapper
@@ -41,7 +41,6 @@
 import androidx.benchmark.perfetto.PerfettoTraceProcessor
 import androidx.benchmark.perfetto.UiState
 import androidx.benchmark.perfetto.appendUiState
-import androidx.benchmark.userspaceTrace
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.tracing.trace
 import java.io.File
@@ -220,7 +219,7 @@
     // Always kill the process at beginning of test
     scope.killProcess()
 
-    userspaceTrace("compile $packageName") {
+    inMemoryTrace("compile $packageName") {
         compilationMode.resetAndCompile(packageName, killProcessBlock = scope::killProcess) {
             setupBlock(scope)
             measureBlock(scope)
@@ -243,12 +242,12 @@
             val runIterations = if (Arguments.dryRunMode) 1 else iterations
             List(runIterations) { iteration ->
                 // Wake the device to ensure it stays awake with large iteration count
-                userspaceTrace("wake device") {
+                inMemoryTrace("wake device") {
                     scope.device.wakeUp()
                 }
 
                 scope.iteration = iteration
-                userspaceTrace("setupBlock") {
+                inMemoryTrace("setupBlock") {
                     setupBlock(scope)
                 }
 
@@ -274,7 +273,8 @@
                         },
                         useStackSamplingConfig = true
                     ),
-                    perfettoSdkConfig = perfettoSdkConfig
+                    perfettoSdkConfig = perfettoSdkConfig,
+                    inMemoryTracingLabel = "Macrobenchmark"
                 ) {
                     try {
                         trace("start metrics") {
@@ -306,7 +306,7 @@
 
                 val measurementList = loadTrace(PerfettoTrace(tracePath)) {
                     // Extracts the metrics using the perfetto trace processor
-                    userspaceTrace("extract metrics") {
+                    inMemoryTrace("extract metrics") {
                         metrics
                             // capture list of Measurements
                             .map {
@@ -330,10 +330,6 @@
                     highlightPackage = packageName
                 )
                 File(tracePath).apply {
-                    // Disabled currently, see b/194424816 and b/174007010
-                    // appendBytes(UserspaceTracing.commitToTrace().encode())
-                    UserspaceTracing.commitToTrace() // clear buffer
-
                     appendUiState(uiState)
                 }
                 Log.d(TAG, "Iteration $iteration captured $uiState")
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
index 7a07561..f77efc40e 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
@@ -5,7 +5,7 @@
 import androidx.benchmark.Outputs
 import androidx.benchmark.Shell
 import androidx.benchmark.getFirstMountedMediaDir
-import androidx.benchmark.userspaceTrace
+import androidx.benchmark.inMemoryTrace
 import androidx.test.platform.app.InstrumentationRegistry
 import java.io.File
 
@@ -73,7 +73,7 @@
     }
 
     private fun broadcast(targetPackageName: String, extras: String) {
-        userspaceTrace("methodTracingBroadcast") {
+        inMemoryTrace("methodTracingBroadcast") {
             val action = "androidx.benchmark.experiments.ACTION_METHOD_TRACE"
             val result =
                 Shell.amBroadcast("-a $action $extras $targetPackageName/$RECEIVER_NAME") ?: 0
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
index e60b36a..4b3ba98 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
@@ -382,7 +382,8 @@
  * Captures the time taken by named trace section - a named begin / end pair matching the provided
  * [sectionName].
  *
- * Select how matching sections are resolved into a duration metric with [mode].
+ * Select how matching sections are resolved into a duration metric with [mode], and configure if
+ * sections outside the target process are included with [targetPackageOnly].
  *
  * @see androidx.tracing.Trace.beginSection
  * @see androidx.tracing.Trace.endSection
@@ -390,8 +391,22 @@
  */
 @ExperimentalMetricApi
 class TraceSectionMetric(
+    /**
+     * Section name or pattern to match.
+     *
+     * "%" can be used as a wildcard, as this is supported by the underlying
+     * [PerfettoTraceProcessor] query. For example `"JIT %"` will match a section named
+     * `"JIT compiling int com.package.MyClass.method(int)"` present in the trace.
+     */
     private val sectionName: String,
-    private val mode: Mode = Mode.First
+    /**
+     * How should the
+     */
+    private val mode: Mode = Mode.First,
+    /**
+     * Filter results to trace sections only from the target process, defaults to true.
+     */
+    private val targetPackageOnly: Boolean = true
 ) : Metric() {
     enum class Mode {
         /**
@@ -425,7 +440,10 @@
         captureInfo: CaptureInfo,
         traceSession: PerfettoTraceProcessor.Session
     ): List<Measurement> {
-        val slices = traceSession.querySlices(sectionName)
+        val slices = traceSession.querySlices(
+            sectionName,
+            packageName = if (targetPackageOnly) captureInfo.targetPackageName else null
+        )
 
         return when (mode) {
             Mode.First -> {
@@ -583,7 +601,7 @@
         traceSession: PerfettoTraceProcessor.Session
     ): List<Measurement> {
         // collect metrics between trace point flags
-        val slice = traceSession.querySlices(MEASURE_BLOCK_SECTION_NAME)
+        val slice = traceSession.querySlices(MEASURE_BLOCK_SECTION_NAME, packageName = null)
             .firstOrNull()
             ?: return emptyList()
 
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt
index 2f74b4c..4fd7b50 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt
@@ -24,8 +24,8 @@
 import androidx.annotation.RequiresApi
 import androidx.benchmark.Shell
 import androidx.benchmark.ShellScript
+import androidx.benchmark.inMemoryTrace
 import androidx.benchmark.perfetto.PerfettoTraceProcessor
-import androidx.benchmark.userspaceTrace
 import java.io.IOException
 import java.io.InputStream
 import java.io.OutputStream
@@ -101,10 +101,10 @@
      * @throws IllegalStateException if the server is not running by the end of the timeout.
      */
     @SuppressLint("BanThreadSleep")
-    fun startServer() = userspaceTrace("PerfettoHttpServer#startServer") {
+    fun startServer() = inMemoryTrace("PerfettoHttpServer#startServer") {
         if (processId != null) {
             Log.w(TAG, "Tried to start a trace shell processor that is already running.")
-            return@userspaceTrace
+            return@inMemoryTrace
         }
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
@@ -168,10 +168,10 @@
     /**
      * Stops the server killing the associated process
      */
-    fun stopServer() = userspaceTrace("PerfettoHttpServer#stopServer") {
+    fun stopServer() = inMemoryTrace("PerfettoHttpServer#stopServer") {
         if (processId == null) {
             Log.w(TAG, "Tried to stop trace shell processor http server without starting it.")
-            return@userspaceTrace
+            return@inMemoryTrace
         }
         Shell.executeScriptSilent("kill -TERM $processId")
         Log.i(TAG, "Perfetto trace processor shell server stopped (pid=$processId).")
@@ -180,10 +180,10 @@
     /**
      * Returns true whether the server is running, false otherwise.
      */
-    fun isRunning(): Boolean = userspaceTrace("PerfettoHttpServer#isRunning") {
-        return@userspaceTrace try {
+    fun isRunning(): Boolean = inMemoryTrace("PerfettoHttpServer#isRunning") {
+        return@inMemoryTrace try {
             val statusResult = status()
-            return@userspaceTrace statusResult.api_version != null && statusResult.api_version > 0
+            return@inMemoryTrace statusResult.api_version != null && statusResult.api_version > 0
         } catch (e: ConnectException) {
             false
         }
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt
index 9314bde..c5bc405 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt
@@ -18,8 +18,8 @@
 
 import androidx.annotation.RestrictTo
 import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
+import androidx.benchmark.inMemoryTrace
 import androidx.benchmark.macro.perfetto.server.PerfettoHttpServer
-import androidx.benchmark.userspaceTrace
 import java.io.File
 import java.io.FileInputStream
 import java.io.InputStream
@@ -93,7 +93,7 @@
         @JvmStatic
         fun <T> runServer(
             block: PerfettoTraceProcessor.() -> T
-        ): T = userspaceTrace("PerfettoTraceProcessor#runServer") {
+        ): T = inMemoryTrace("PerfettoTraceProcessor#runServer") {
             var perfettoTraceProcessor: PerfettoTraceProcessor? = null
             try {
 
@@ -101,7 +101,7 @@
                 perfettoTraceProcessor = PerfettoTraceProcessor().startServer()
 
                 // Executes the query block
-                return@userspaceTrace userspaceTrace("PerfettoTraceProcessor#runServer#block") {
+                return@inMemoryTrace inMemoryTrace("PerfettoTraceProcessor#runServer#block") {
                     block(perfettoTraceProcessor)
                 }
             } finally {
@@ -145,7 +145,7 @@
          */
         @RestrictTo(LIBRARY_GROUP) // avoids exposing Proto API
         fun getTraceMetrics(metric: String): TraceMetrics {
-            userspaceTrace("PerfettoTraceProcessor#getTraceMetrics $metric") {
+            inMemoryTrace("PerfettoTraceProcessor#getTraceMetrics $metric") {
                 require(!metric.contains(" ")) {
                     "Metric must not contain spaces: $metric"
                 }
@@ -186,7 +186,7 @@
          * @see PerfettoTraceProcessor.Session
          */
         fun query(@Language("sql") query: String): Sequence<Row> {
-            userspaceTrace("PerfettoTraceProcessor#query $query".take(127)) {
+            inMemoryTrace("PerfettoTraceProcessor#query $query".take(127)) {
                 require(traceProcessor.perfettoHttpServer.isRunning()) {
                     "Perfetto trace_shell_process is not running."
                 }
@@ -224,7 +224,7 @@
          * @see Session.query
          */
         fun rawQuery(@Language("sql") query: String): ByteArray {
-            userspaceTrace("PerfettoTraceProcessor#query $query".take(127)) {
+            inMemoryTrace("PerfettoTraceProcessor#query $query".take(127)) {
                 require(traceProcessor.perfettoHttpServer.isRunning()) {
                     "Perfetto trace_shell_process is not running."
                 }
@@ -238,21 +238,43 @@
          * Note that sliceNames may include wildcard matches, such as `foo%`
          */
         @RestrictTo(LIBRARY_GROUP) // Slice API not currently exposed, since it doesn't track table
-        fun querySlices(vararg sliceNames: String): List<Slice> {
+        fun querySlices(
+            vararg sliceNames: String,
+            packageName: String?,
+        ): List<Slice> {
             require(traceProcessor.perfettoHttpServer.isRunning()) {
                 "Perfetto trace_shell_process is not running."
             }
 
             val whereClause = sliceNames
-                .joinToString(separator = " OR ") {
+                .joinToString(
+                    separator = " OR ",
+                    prefix = if (packageName == null) {
+                        "("
+                    } else {
+                        processNameLikePkg(packageName) + " AND ("
+                    },
+                    postfix = ")"
+                ) {
                     "slice.name LIKE \"$it\""
                 }
+            val innerJoins = if (packageName != null) {
+                """
+                INNER JOIN thread_track on slice.track_id = thread_track.id
+                INNER JOIN thread USING(utid)
+                INNER JOIN process USING(upid)
+                """.trimMargin()
+            } else {
+                ""
+            }
 
             return query(
                 query = """
                     SELECT slice.name,ts,dur
                     FROM slice
+                    $innerJoins
                     WHERE $whereClause
+                    ORDER BY ts
                     """.trimMargin()
             ).toSlices()
         }
@@ -262,13 +284,13 @@
     private var traceLoaded = false
 
     private fun startServer(): PerfettoTraceProcessor =
-        userspaceTrace("PerfettoTraceProcessor#startServer") {
+        inMemoryTrace("PerfettoTraceProcessor#startServer") {
             println("startserver")
             perfettoHttpServer.startServer()
-            return@userspaceTrace this
+            return@inMemoryTrace this
         }
 
-    private fun stopServer() = userspaceTrace("PerfettoTraceProcessor#stopServer") {
+    private fun stopServer() = inMemoryTrace("PerfettoTraceProcessor#stopServer") {
         println("stopserver")
         perfettoHttpServer.stopServer()
     }
@@ -278,7 +300,7 @@
      * trace if existing.
      */
     private fun loadTraceImpl(absoluteTracePath: String) {
-        userspaceTrace("PerfettoTraceProcessor#loadTraceImpl") {
+        inMemoryTrace("PerfettoTraceProcessor#loadTraceImpl") {
             require(!absoluteTracePath.contains(" ")) {
                 "Trace path must not contain spaces: $absoluteTracePath"
             }
@@ -306,7 +328,7 @@
     /**
      * Clears the current loaded trace.
      */
-    private fun clearTrace() = userspaceTrace("PerfettoTraceProcessor#clearTrace") {
+    private fun clearTrace() = inMemoryTrace("PerfettoTraceProcessor#clearTrace") {
         perfettoHttpServer.restoreInitialTables()
         traceLoaded = false
     }
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt
index 8fb6552..34276ac 100644
--- a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt
@@ -50,7 +50,7 @@
      * the legacy advertise limit (31 bytes)
      */
     @Test
-    fun advertiseTooLargeDataO() = runTest {
+    fun advertiseTooLargeData() = runTest {
         val parcelUuid = UUID.randomUUID()
         val serviceData = "sampleAdvertiseDataTooLargeToAdvertise".toByteArray(Charsets.UTF_8)
 
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt
new file mode 100644
index 0000000..dddad2d
--- /dev/null
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt
@@ -0,0 +1,232 @@
+/*
+ * 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.bluetooth.testing
+
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice as FwkDevice
+import android.bluetooth.BluetoothGatt
+import android.bluetooth.BluetoothGattCallback
+import android.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattDescriptor
+import android.bluetooth.BluetoothGattService
+import android.bluetooth.BluetoothManager
+import android.content.Context
+import androidx.bluetooth.BluetoothDevice
+import androidx.bluetooth.BluetoothLe
+import androidx.bluetooth.GattClient
+import java.util.UUID
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.RuntimeEnvironment
+import org.robolectric.Shadows.shadowOf
+import org.robolectric.shadows.ShadowBluetoothGatt
+
+@RunWith(RobolectricTestRunner::class)
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+class RobolectricGattClientTest {
+    private val context: Context = RuntimeEnvironment.getApplication()
+    private val bluetoothManager: BluetoothManager =
+        context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
+    private val bluetoothAdapter: BluetoothAdapter? = bluetoothManager.adapter
+    private lateinit var bluetoothLe: BluetoothLe
+    private lateinit var clientAdapter: StubClientFrameworkAdapter
+
+    private companion object {
+        private val serviceUuid1 = UUID.fromString("00001111-0000-1000-8000-00805F9B34FB")
+        private val serviceUuid2 = UUID.fromString("00001112-0000-1000-8000-00805F9B34FB")
+
+        private val service1 = BluetoothGattService(serviceUuid1,
+            BluetoothGattService.SERVICE_TYPE_PRIMARY)
+        private val service2 = BluetoothGattService(serviceUuid2,
+            BluetoothGattService.SERVICE_TYPE_PRIMARY)
+
+        private val sampleServices: List<BluetoothGattService> = listOf(service1, service2)
+    }
+
+    @Before
+    fun setUp() {
+        bluetoothLe = BluetoothLe(context)
+        clientAdapter = StubClientFrameworkAdapter(bluetoothLe.client.fwkAdapter)
+        bluetoothLe.client.fwkAdapter = clientAdapter
+    }
+
+    @Test
+    fun connectGatt() = runTest {
+        acceptConnect()
+        val device = createDevice("00:11:22:33:44:55")
+        Assert.assertEquals(true, bluetoothLe.connectGatt(device) {
+            Assert.assertEquals(sampleServices.size, getServices().size)
+            sampleServices.forEachIndexed { index, service ->
+                Assert.assertEquals(service.uuid, getServices()[index].uuid)
+            }
+            true
+        }.getOrNull())
+    }
+
+    @Test
+    fun connectFail() = runTest {
+        val device = createDevice("00:11:22:33:44:55")
+        rejectConnect()
+        Assert.assertEquals(true, bluetoothLe.connectGatt(device) { true }.isFailure)
+    }
+
+    private fun acceptConnect() {
+        clientAdapter.onConnectListener =
+            StubClientFrameworkAdapter.OnConnectListener { device, _ ->
+            shadowOf(device).simulateGattConnectionChange(
+                BluetoothGatt.GATT_SUCCESS, BluetoothGatt.STATE_CONNECTED
+            )
+            true
+        }
+
+        clientAdapter.onRequestMtuListener =
+            StubClientFrameworkAdapter.OnRequestMtuListener { mtu ->
+            clientAdapter.callback?.onMtuChanged(clientAdapter.bluetoothGatt, mtu,
+                BluetoothGatt.GATT_SUCCESS)
+        }
+
+        clientAdapter.onDiscoverServicesListener =
+            StubClientFrameworkAdapter.OnDiscoverServicesListener {
+            clientAdapter.gattServices = sampleServices
+            clientAdapter.callback?.onServicesDiscovered(clientAdapter.bluetoothGatt,
+                BluetoothGatt.GATT_SUCCESS)
+        }
+    }
+
+    private fun rejectConnect() {
+        clientAdapter.onConnectListener =
+            StubClientFrameworkAdapter.OnConnectListener { device, _ ->
+            shadowOf(device).simulateGattConnectionChange(
+                BluetoothGatt.GATT_FAILURE, BluetoothGatt.STATE_DISCONNECTED
+            )
+            false
+        }
+    }
+
+    private fun createDevice(address: String): BluetoothDevice {
+       return BluetoothDevice(bluetoothAdapter!!.getRemoteDevice(address))
+    }
+
+    class StubClientFrameworkAdapter(
+        private val baseAdapter: GattClient.FrameworkAdapter
+    ) : GattClient.FrameworkAdapter {
+        var gattServices: List<BluetoothGattService> = listOf()
+        var callback: BluetoothGattCallback? = null
+        override var bluetoothGatt: BluetoothGatt?
+            get() = baseAdapter.bluetoothGatt
+            set(value) { baseAdapter.bluetoothGatt = value }
+        val shadowBluetoothGatt: ShadowBluetoothGatt
+            get() = shadowOf(bluetoothGatt)
+
+        var onConnectListener: OnConnectListener? = null
+        var onRequestMtuListener: OnRequestMtuListener? = null
+        var onDiscoverServicesListener: OnDiscoverServicesListener? = null
+        var onReadCharacteristicListener: OnReadCharacteristicListener? = null
+        var onWriteCharacteristicListener: OnWriteCharacteristicListener? = null
+        var onWriteDescriptorListener: OnWriteDescriptorListener? = null
+        var onSetCharacteristicNotifiationListener: OnSetCharacteristicNotificationListener? = null
+
+        override fun connectGatt(
+            context: Context,
+            device: FwkDevice,
+            callback: BluetoothGattCallback
+        ): Boolean {
+            this.callback = callback
+            baseAdapter.connectGatt(context, device, callback)
+            return onConnectListener?.onConnect(device, callback) ?: false
+        }
+
+        override fun requestMtu(mtu: Int) {
+            baseAdapter.requestMtu(mtu)
+            onRequestMtuListener?.onRequestMtu(mtu)
+        }
+
+        override fun discoverServices() {
+            baseAdapter.discoverServices()
+            onDiscoverServicesListener?.onDiscoverServices()
+        }
+
+        override fun getServices(): List<BluetoothGattService> {
+            return gattServices
+        }
+
+        override fun getService(uuid: UUID): BluetoothGattService? {
+            return gattServices.find { it.uuid == uuid }
+        }
+
+        override fun readCharacteristic(characteristic: BluetoothGattCharacteristic) {
+            baseAdapter.readCharacteristic(characteristic)
+            onReadCharacteristicListener?.onReadCharacteristic(characteristic)
+        }
+
+        override fun writeCharacteristic(
+            characteristic: BluetoothGattCharacteristic,
+            value: ByteArray,
+            writeType: Int
+        ) {
+            baseAdapter.writeCharacteristic(characteristic, value, writeType)
+            onWriteCharacteristicListener?.onWriteCharacteristic(characteristic, value, writeType)
+        }
+
+        override fun writeDescriptor(descriptor: BluetoothGattDescriptor, value: ByteArray) {
+            baseAdapter.writeDescriptor(descriptor, value)
+            onWriteDescriptorListener?.onWriteDescriptor(descriptor, value)
+        }
+
+        override fun setCharacteristicNotification(
+            characteristic: BluetoothGattCharacteristic,
+            enable: Boolean
+        ) {
+            baseAdapter.setCharacteristicNotification(characteristic, enable)
+            onSetCharacteristicNotifiationListener
+                ?.onSetCharacteristicNotification(characteristic, enable)
+        }
+
+        fun interface OnConnectListener {
+            fun onConnect(device: FwkDevice, callback: BluetoothGattCallback): Boolean
+        }
+        fun interface OnRequestMtuListener {
+            fun onRequestMtu(mtu: Int)
+        }
+        fun interface OnDiscoverServicesListener {
+            fun onDiscoverServices()
+        }
+        fun interface OnReadCharacteristicListener {
+            fun onReadCharacteristic(characteristic: BluetoothGattCharacteristic)
+        }
+        fun interface OnWriteCharacteristicListener {
+            fun onWriteCharacteristic(
+                characteristic: BluetoothGattCharacteristic,
+                value: ByteArray,
+                writeType: Int
+            )
+        }
+        fun interface OnWriteDescriptorListener {
+            fun onWriteDescriptor(descriptor: BluetoothGattDescriptor, value: ByteArray)
+        }
+        fun interface OnSetCharacteristicNotificationListener {
+            fun onSetCharacteristicNotification(
+                characteristic: BluetoothGattCharacteristic,
+                enable: Boolean
+            )
+        }
+    }
+}
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt
index 283bc1d..1dd57c9 100644
--- a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt
@@ -38,7 +38,7 @@
     }
 
     @Test
-    fun scanTest() = runTest {
+    fun scan() = runTest {
         try {
             withTimeout(TIMEOUT_MS) {
                 bluetoothLe.scan(listOf(ScanFilter())).collect {
diff --git a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothDeviceTest.kt b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothDeviceTest.kt
index 98eeb61..9e8956d 100644
--- a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothDeviceTest.kt
+++ b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothDeviceTest.kt
@@ -55,7 +55,7 @@
         Assume.assumeNotNull(bluetoothAdapter) // Bluetooth is not available if adapter is null
         val fwkBluetoothDevice = bluetoothAdapter!!.getRemoteDevice("00:01:02:03:04:05")
 
-        val bluetoothDevice = BluetoothDevice.of(fwkBluetoothDevice)
+        val bluetoothDevice = BluetoothDevice(fwkBluetoothDevice)
 
         assertEquals(bluetoothDevice.bondState, fwkBluetoothDevice.bondState)
         assertEquals(bluetoothDevice.name, fwkBluetoothDevice.name)
diff --git a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt
index 9df2442..2e7b1fd 100644
--- a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt
+++ b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt
@@ -53,8 +53,8 @@
             timeStampNanos)
         val scanResult = ScanResult(fwkScanResult)
 
-        assertEquals(scanResult.device.name, BluetoothDevice.of(fwkBluetoothDevice).name)
-        assertEquals(scanResult.device.bondState, BluetoothDevice.of(fwkBluetoothDevice).bondState)
+        assertEquals(scanResult.device.name, BluetoothDevice(fwkBluetoothDevice).name)
+        assertEquals(scanResult.device.bondState, BluetoothDevice(fwkBluetoothDevice).bondState)
         assertEquals(scanResult.deviceAddress.address, address)
         assertEquals(scanResult.deviceAddress.addressType,
             BluetoothAddress.ADDRESS_TYPE_RANDOM_STATIC)
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothDevice.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothDevice.kt
index 2cc4340..2c34db7 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothDevice.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothDevice.kt
@@ -30,14 +30,9 @@
  * @property bondState the bondState for this BluetoothDevice
  *
  */
-class BluetoothDevice private constructor(
+class BluetoothDevice @RestrictTo(RestrictTo.Scope.LIBRARY) constructor(
     internal val fwkDevice: FwkBluetoothDevice
 ) {
-    internal companion object {
-        fun of(device: FwkBluetoothDevice): BluetoothDevice {
-            return BluetoothDevice(device)
-        }
-    }
     val id: UUID = UUID.randomUUID()
 
     @get:RequiresPermission(
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
index 24b5d0d..cc95ef8 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
@@ -28,6 +28,7 @@
 import android.util.Log
 import androidx.annotation.RequiresPermission
 import androidx.annotation.RestrictTo
+import androidx.annotation.VisibleForTesting
 import java.util.UUID
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.channels.awaitClose
@@ -39,7 +40,7 @@
  * operations such as scanning, advertising, and connection with a respective [BluetoothDevice].
  *
  */
-class BluetoothLe(private val context: Context) {
+class BluetoothLe constructor(private val context: Context) {
 
     private companion object {
         private const val TAG = "BluetoothLe"
@@ -48,6 +49,10 @@
     private val bluetoothManager =
         context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?
     private val bluetoothAdapter = bluetoothManager?.adapter
+
+    @VisibleForTesting
+    @get:RestrictTo(RestrictTo.Scope.LIBRARY)
+    val client = GattClient(context)
     private val server = GattServer(context)
 
     /**
@@ -226,7 +231,7 @@
         device: BluetoothDevice,
         block: suspend GattClientScope.() -> R
     ): Result<R> {
-        return GattClient().connect(context, device, block)
+        return client.connect(device, block)
     }
 
     /**
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt
index ab2b0df..411d947 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt
@@ -27,6 +27,8 @@
 import android.content.Context
 import android.os.Build
 import androidx.annotation.RequiresPermission
+import androidx.annotation.RestrictTo
+import androidx.annotation.VisibleForTesting
 import java.util.UUID
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.CompletableDeferred
@@ -48,13 +50,18 @@
 /**
  * A class for handling operations as a GATT client role.
  */
-internal class GattClient {
-    private interface GattClientImpl {
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class GattClient(private val context: Context) {
+    interface FrameworkAdapter {
+        var bluetoothGatt: BluetoothGatt?
         fun connectGatt(
             context: Context,
             device: FwkDevice,
             callback: BluetoothGattCallback
         ): Boolean
+        fun requestMtu(mtu: Int)
+
+        fun discoverServices()
 
         fun getServices(): List<FwkService>
         fun getService(uuid: UUID): FwkService?
@@ -70,7 +77,9 @@
         fun setCharacteristicNotification(characteristic: FwkCharacteristic, enable: Boolean)
     }
 
-    private companion object {
+    @VisibleForTesting
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    companion object {
         private const val TAG = "GattClient"
 
         /**
@@ -81,9 +90,11 @@
     }
 
     @SuppressLint("ObsoleteSdkInt")
-    private val impl: GattClientImpl =
-        if (Build.VERSION.SDK_INT >= 33) GattClientImplApi33()
-        else BaseGattClientImpl()
+    @VisibleForTesting
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    var fwkAdapter: FrameworkAdapter =
+        if (Build.VERSION.SDK_INT >= 33) FrameworkAdapterApi33()
+        else FrameworkAdapterBase()
 
     private sealed interface CallbackResult {
         class OnCharacteristicRead(
@@ -116,7 +127,6 @@
 
     @SuppressLint("MissingPermission")
     suspend fun <R> connect(
-        context: Context,
         device: BluetoothDevice,
         block: suspend BluetoothLe.GattClientScope.() -> R
     ): Result<R> = coroutineScope {
@@ -130,7 +140,7 @@
         val callback = object : BluetoothGattCallback() {
             override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
                 if (newState == BluetoothGatt.STATE_CONNECTED) {
-                    gatt?.requestMtu(GATT_MAX_MTU)
+                    fwkAdapter.requestMtu(GATT_MAX_MTU)
                 } else {
                     connectResult.cancel("connect failed")
                 }
@@ -138,16 +148,14 @@
 
             override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
                 if (status == BluetoothGatt.GATT_SUCCESS) {
-                    gatt?.discoverServices()
+                    fwkAdapter.discoverServices()
                 } else {
                     connectResult.cancel("mtu request failed")
                 }
             }
 
             override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
-                gatt?.let {
-                    attributeMap.updateWithFrameworkServices(it.services)
-                }
+                attributeMap.updateWithFrameworkServices(fwkAdapter.getServices())
                 if (status == BluetoothGatt.GATT_SUCCESS) connectResult.complete(Unit)
                 else connectResult.cancel("service discover failed")
             }
@@ -208,7 +216,7 @@
                 }
             }
         }
-        if (!impl.connectGatt(context, device.fwkDevice, callback)) {
+        if (!fwkAdapter.connectGatt(context, device.fwkDevice, callback)) {
             return@coroutineScope Result.failure(CancellationException("failed to connect"))
         }
 
@@ -230,7 +238,7 @@
             }
 
             override fun getService(uuid: UUID): GattService? {
-                return impl.getService(uuid)?.let { attributeMap.fromFwkService(it) }
+                return fwkAdapter.getService(uuid)?.let { attributeMap.fromFwkService(it) }
             }
 
             override suspend fun readCharacteristic(characteristic: GattCharacteristic):
@@ -239,7 +247,7 @@
                     return Result.failure(IllegalArgumentException("can't read the characteristic"))
                 }
                 return runTask {
-                    impl.readCharacteristic(characteristic.fwkCharacteristic)
+                    fwkAdapter.readCharacteristic(characteristic.fwkCharacteristic)
                     val res = takeMatchingResult<CallbackResult.OnCharacteristicRead>(
                         callbackResultsFlow
                     ) {
@@ -263,7 +271,8 @@
                     )
                 }
                 return runTask {
-                    impl.writeCharacteristic(characteristic.fwkCharacteristic, value, writeType)
+                    fwkAdapter.writeCharacteristic(
+                        characteristic.fwkCharacteristic, value, writeType)
                     val res = takeMatchingResult<CallbackResult.OnCharacteristicWrite>(
                         callbackResultsFlow
                     ) {
@@ -298,11 +307,11 @@
                     }
 
                     runTask {
-                        impl.setCharacteristicNotification(
+                        fwkAdapter.setCharacteristicNotification(
                             characteristic.fwkCharacteristic, /*enable=*/true
                         )
 
-                        impl.writeDescriptor(cccd, FwkDescriptor.ENABLE_NOTIFICATION_VALUE)
+                        fwkAdapter.writeDescriptor(cccd, FwkDescriptor.ENABLE_NOTIFICATION_VALUE)
                         val res = takeMatchingResult<CallbackResult.OnDescriptorWrite>(
                             callbackResultsFlow
                         ) {
@@ -317,11 +326,11 @@
                         launch {
                             unregisterSubscribeListener(characteristic.fwkCharacteristic)
                         }
-                        impl.setCharacteristicNotification(
+                        fwkAdapter.setCharacteristicNotification(
                             characteristic.fwkCharacteristic, /*enable=*/false
                         )
 
-                        impl.writeDescriptor(cccd, FwkDescriptor.DISABLE_NOTIFICATION_VALUE)
+                        fwkAdapter.writeDescriptor(cccd, FwkDescriptor.DISABLE_NOTIFICATION_VALUE)
                     }
                 }
             }
@@ -374,8 +383,8 @@
         return flow.filter { it is R && predicate(it) }.first() as R
     }
 
-    private open class BaseGattClientImpl : GattClientImpl {
-        var bluetoothGatt: BluetoothGatt? = null
+    private open class FrameworkAdapterBase : FrameworkAdapter {
+        override var bluetoothGatt: BluetoothGatt? = null
 
         @RequiresPermission(BLUETOOTH_CONNECT)
         override fun connectGatt(
@@ -387,6 +396,16 @@
             return bluetoothGatt != null
         }
 
+        @RequiresPermission(BLUETOOTH_CONNECT)
+        override fun requestMtu(mtu: Int) {
+            bluetoothGatt?.requestMtu(mtu)
+        }
+
+        @RequiresPermission(BLUETOOTH_CONNECT)
+        override fun discoverServices() {
+            bluetoothGatt?.discoverServices()
+        }
+
         override fun getServices(): List<FwkService> {
             return bluetoothGatt?.services ?: listOf()
         }
@@ -427,7 +446,7 @@
         }
     }
 
-    private open class GattClientImplApi33 : BaseGattClientImpl() {
+    private open class FrameworkAdapterApi33 : FrameworkAdapterBase() {
         @RequiresPermission(BLUETOOTH_CONNECT)
         override fun writeCharacteristic(
             characteristic: FwkCharacteristic,
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt
index 0c22a3b..785983d 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt
@@ -99,7 +99,7 @@
                     BluetoothProfile.STATE_CONNECTED -> {
                         trySend(
                             BluetoothLe.GattServerConnectionRequest(
-                                BluetoothDevice.of(device),
+                                BluetoothDevice(device),
                                 this@GattServer,
                                 addSession(device)
                             )
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt
index f98714b..045b3de 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt
@@ -39,7 +39,7 @@
 
     /** Remote Bluetooth device found. */
     val device: BluetoothDevice
-        get() = BluetoothDevice.of(fwkScanResult.device)
+        get() = BluetoothDevice(fwkScanResult.device)
 
     // TODO(kihongs) Find a way to get address type from framework scan result
     /** Bluetooth address for the remote device found. */
diff --git a/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt b/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt
index e4d7736..8d92531 100644
--- a/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt
+++ b/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt
@@ -350,6 +350,7 @@
     <option name="wifi:disable" value="true" />
     <option name="instrumentation-arg" key="notAnnotation" value="androidx.test.filters.FlakyTest" />
     <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.InstrumentationResultsRunListener" />
+    <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.SideEffectRunListener" />
     <include name="google/unbundled/common/setup" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
     <option name="cleanup-apks" value="true" />
@@ -358,6 +359,7 @@
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
     <option name="run-command" value="cmd package compile -f -m speed com.androidx.placeholder.Placeholder" />
+    <option name="run-command-timeout" value="240000" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
     <option name="runner" value="com.example.Runner"/>
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt
index 657f702..90fd4df 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt
@@ -242,6 +242,7 @@
     """
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
     <option name="run-command" value="${benchmarkPostInstallCommand(packageName)}" />
+    <option name="run-command-timeout" value="240000" />
     </target_preparer>
 
 """.trimIndent()
@@ -323,6 +324,7 @@
 private val MICROBENCHMARK_POSTSUBMIT_OPTIONS =
     """
     <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.InstrumentationResultsRunListener" />
+    <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.SideEffectRunListener" />
 
 """
         .trimIndent()
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java
index 86ce8a9..4f64bb4 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java
@@ -193,8 +193,8 @@
 
     @NonNull
     @Override
-    public ListenableFuture<Integer> setExposureCompensationIndex(int exposure) {
-        mExposureCompensation = exposure;
+    public ListenableFuture<Integer> setExposureCompensationIndex(int value) {
+        mExposureCompensation = value;
         return Futures.immediateFuture(null);
     }
 
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/mocks/MockConsumer.java b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/mocks/MockConsumer.java
index 904e34e..c3c8932 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/mocks/MockConsumer.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/mocks/MockConsumer.java
@@ -261,8 +261,8 @@
     }
 
     @Override
-    public void accept(T event) {
-        mEventList.add(event);
+    public void accept(T t) {
+        mEventList.add(t);
 
         synchronized (mLock) {
             if (mLatch != null && isVerified(mEventList)) {
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/AudioSource.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/AudioSource.java
index a4b0e4e4..2b78756 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/AudioSource.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/AudioSource.java
@@ -469,7 +469,7 @@
                                 NANOSECONDS.toMicros(packetInfo.getTimestampNs()));
                         inputBuffer.submit();
                     } else {
-                        Logger.w(TAG, "Unable to read data from AudioRecord.");
+                        Logger.w(TAG, "Unable to read data from AudioStream.");
                         inputBuffer.cancel();
                     }
                     sendNextAudio();
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/BufferedAudioStream.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/BufferedAudioStream.java
index 7c3d659..bbd013b 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/BufferedAudioStream.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/BufferedAudioStream.java
@@ -21,6 +21,8 @@
 import static androidx.core.util.Preconditions.checkArgument;
 import static androidx.core.util.Preconditions.checkState;
 
+import android.annotation.SuppressLint;
+
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -55,6 +57,7 @@
     private static final String TAG = "BufferedAudioStream";
     private static final int DEFAULT_BUFFER_SIZE_IN_FRAME = 1024;
     private static final int DEFAULT_QUEUE_SIZE = 500;
+    private static final int DATA_WAITING_TIME_MILLIS = 1;
 
     private final AtomicBoolean mIsStarted = new AtomicBoolean(false);
     private final AtomicBoolean mIsReleased = new AtomicBoolean(false);
@@ -151,6 +154,7 @@
         });
     }
 
+    @SuppressLint("BanThreadSleep")
     @NonNull
     @Override
     public PacketInfo read(@NonNull ByteBuffer byteBuffer) {
@@ -160,24 +164,40 @@
         // Match collection buffer size and read buffer size to improve read efficiency.
         updateCollectionBufferSizeAsync(byteBuffer.remaining());
 
+        // Block the thread till the audio data is actually read.
+        boolean isWaitingForData;
         PacketInfo packetInfo = PacketInfo.of(0, 0);
-        synchronized (mLock) {
-            AudioData audioData = mAudioDataNotFullyRead;
-            mAudioDataNotFullyRead = null;
-            if (audioData == null) {
-                audioData = mAudioDataQueue.poll();
-            }
-
-            if (audioData != null) {
-                packetInfo = audioData.read(byteBuffer);
-
-                if (audioData.getRemainingBufferSizeInBytes() > 0) {
-                    mAudioDataNotFullyRead = audioData;
+        do {
+            synchronized (mLock) {
+                AudioData audioData = mAudioDataNotFullyRead;
+                mAudioDataNotFullyRead = null;
+                if (audioData == null) {
+                    audioData = mAudioDataQueue.poll();
                 }
-            } else {
-                Logger.d(TAG, "No data to read.");
+
+                if (audioData != null) {
+                    packetInfo = audioData.read(byteBuffer);
+
+                    if (audioData.getRemainingBufferSizeInBytes() > 0) {
+                        mAudioDataNotFullyRead = audioData;
+                    }
+                }
             }
-        }
+
+            // Wait for data collection if no data to read and the audio stream is still running.
+            isWaitingForData =
+                    packetInfo.getSizeInBytes() <= 0 && mIsStarted.get() && !mIsReleased.get();
+
+            // Sleep to prevent busy accessing to variables.
+            if (isWaitingForData) {
+                try {
+                    Thread.sleep(DATA_WAITING_TIME_MILLIS);
+                } catch (InterruptedException e) {
+                    Logger.w(TAG, "Interruption while waiting for audio data", e);
+                    break;
+                }
+            }
+        } while (isWaitingForData);
 
         return packetInfo;
     }
diff --git a/car/app/app-automotive/api/1.4.0-beta01.txt b/car/app/app-automotive/api/1.4.0-beta01.txt
new file mode 100644
index 0000000..33c4502
--- /dev/null
+++ b/car/app/app-automotive/api/1.4.0-beta01.txt
@@ -0,0 +1,101 @@
+// Signature format: 4.0
+package androidx.car.app.activity {
+
+  public abstract class BaseCarAppActivity extends androidx.fragment.app.FragmentActivity implements androidx.lifecycle.LifecycleOwner {
+    ctor public BaseCarAppActivity();
+    method public void bindToViewModel(androidx.car.app.SessionInfo);
+    method public android.content.ComponentName? getServiceComponentName();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public android.content.ComponentName? retrieveServiceComponentName();
+  }
+
+  public final class CarAppActivity extends androidx.car.app.activity.BaseCarAppActivity implements androidx.lifecycle.LifecycleOwner {
+    ctor public CarAppActivity();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class LauncherActivity extends androidx.fragment.app.FragmentActivity implements androidx.lifecycle.LifecycleOwner {
+    ctor public LauncherActivity();
+  }
+
+}
+
+package androidx.car.app.activity.renderer.surface {
+
+  @SuppressCompatibility public final class LegacySurfacePackage {
+    ctor public LegacySurfacePackage(androidx.car.app.activity.renderer.surface.SurfaceControlCallback);
+  }
+
+  public interface SurfaceControlCallback {
+    method public default void onError(String, Throwable);
+    method public void onKeyEvent(android.view.KeyEvent);
+    method public void onTouchEvent(android.view.MotionEvent);
+    method public void onWindowFocusChanged(boolean, boolean);
+    method public void setSurfaceWrapper(androidx.car.app.activity.renderer.surface.SurfaceWrapper);
+  }
+
+  @SuppressCompatibility public final class SurfaceWrapper {
+    ctor public SurfaceWrapper(android.os.IBinder?, @Dimension int, @Dimension int, int, int, android.view.Surface);
+    method public int getDensityDpi();
+    method public int getDisplayId();
+    method @Dimension public int getHeight();
+    method public android.os.IBinder? getHostToken();
+    method public android.view.Surface getSurface();
+    method @Dimension public int getWidth();
+  }
+
+}
+
+package androidx.car.app.hardware {
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class AutomotiveCarHardwareManager implements androidx.car.app.hardware.CarHardwareManager {
+    ctor public AutomotiveCarHardwareManager(android.content.Context);
+  }
+
+}
+
+package androidx.car.app.hardware.common {
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneAreaIdConstants {
+    field public static final int AREA_ID_GLOBAL = 0; // 0x0
+  }
+
+  public static final class CarZoneAreaIdConstants.VehicleAreaSeat {
+    field public static final int COL_ALL = 1911; // 0x777
+    field public static final int COL_CENTER = 546; // 0x222
+    field public static final int COL_LEFT = 273; // 0x111
+    field public static final int COL_RIGHT = 1092; // 0x444
+    field public static final int ROW_1_CENTER = 2; // 0x2
+    field public static final int ROW_1_LEFT = 1; // 0x1
+    field public static final int ROW_1_RIGHT = 4; // 0x4
+    field public static final int ROW_2_CENTER = 32; // 0x20
+    field public static final int ROW_2_LEFT = 16; // 0x10
+    field public static final int ROW_2_RIGHT = 64; // 0x40
+    field public static final int ROW_3_CENTER = 512; // 0x200
+    field public static final int ROW_3_LEFT = 256; // 0x100
+    field public static final int ROW_3_RIGHT = 1024; // 0x400
+    field public static final int ROW_ALL = 1911; // 0x777
+    field public static final int ROW_FIRST = 7; // 0x7
+    field public static final int ROW_SECOND = 112; // 0x70
+    field public static final int ROW_THIRD = 1792; // 0x700
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public interface CarZoneAreaIdConverter {
+    method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneUtils {
+    method public static com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int, int);
+    method public static androidx.car.app.hardware.common.CarZoneAreaIdConverter getZoneAreaIdConverter(int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class GlobalCarZoneAreaIdConverter implements androidx.car.app.hardware.common.CarZoneAreaIdConverter {
+    ctor public GlobalCarZoneAreaIdConverter();
+    method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class SeatCarZoneAreaIdConverter implements androidx.car.app.hardware.common.CarZoneAreaIdConverter {
+    ctor public SeatCarZoneAreaIdConverter();
+    method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+  }
+
+}
+
diff --git a/car/app/app-automotive/api/res-1.4.0-beta01.txt b/car/app/app-automotive/api/res-1.4.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/car/app/app-automotive/api/res-1.4.0-beta01.txt
diff --git a/car/app/app-automotive/api/restricted_1.4.0-beta01.txt b/car/app/app-automotive/api/restricted_1.4.0-beta01.txt
new file mode 100644
index 0000000..433cb93
--- /dev/null
+++ b/car/app/app-automotive/api/restricted_1.4.0-beta01.txt
@@ -0,0 +1,101 @@
+// Signature format: 4.0
+package androidx.car.app.activity {
+
+  public abstract class BaseCarAppActivity extends androidx.fragment.app.FragmentActivity {
+    ctor public BaseCarAppActivity();
+    method public void bindToViewModel(androidx.car.app.SessionInfo);
+    method public android.content.ComponentName? getServiceComponentName();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public android.content.ComponentName? retrieveServiceComponentName();
+  }
+
+  public final class CarAppActivity extends androidx.car.app.activity.BaseCarAppActivity {
+    ctor public CarAppActivity();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class LauncherActivity extends androidx.fragment.app.FragmentActivity {
+    ctor public LauncherActivity();
+  }
+
+}
+
+package androidx.car.app.activity.renderer.surface {
+
+  @SuppressCompatibility public final class LegacySurfacePackage {
+    ctor public LegacySurfacePackage(androidx.car.app.activity.renderer.surface.SurfaceControlCallback);
+  }
+
+  public interface SurfaceControlCallback {
+    method public default void onError(String, Throwable);
+    method public void onKeyEvent(android.view.KeyEvent);
+    method public void onTouchEvent(android.view.MotionEvent);
+    method public void onWindowFocusChanged(boolean, boolean);
+    method public void setSurfaceWrapper(androidx.car.app.activity.renderer.surface.SurfaceWrapper);
+  }
+
+  @SuppressCompatibility public final class SurfaceWrapper {
+    ctor public SurfaceWrapper(android.os.IBinder?, @Dimension int, @Dimension int, int, int, android.view.Surface);
+    method public int getDensityDpi();
+    method public int getDisplayId();
+    method @Dimension public int getHeight();
+    method public android.os.IBinder? getHostToken();
+    method public android.view.Surface getSurface();
+    method @Dimension public int getWidth();
+  }
+
+}
+
+package androidx.car.app.hardware {
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class AutomotiveCarHardwareManager implements androidx.car.app.hardware.CarHardwareManager {
+    ctor public AutomotiveCarHardwareManager(android.content.Context);
+  }
+
+}
+
+package androidx.car.app.hardware.common {
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneAreaIdConstants {
+    field public static final int AREA_ID_GLOBAL = 0; // 0x0
+  }
+
+  public static final class CarZoneAreaIdConstants.VehicleAreaSeat {
+    field public static final int COL_ALL = 1911; // 0x777
+    field public static final int COL_CENTER = 546; // 0x222
+    field public static final int COL_LEFT = 273; // 0x111
+    field public static final int COL_RIGHT = 1092; // 0x444
+    field public static final int ROW_1_CENTER = 2; // 0x2
+    field public static final int ROW_1_LEFT = 1; // 0x1
+    field public static final int ROW_1_RIGHT = 4; // 0x4
+    field public static final int ROW_2_CENTER = 32; // 0x20
+    field public static final int ROW_2_LEFT = 16; // 0x10
+    field public static final int ROW_2_RIGHT = 64; // 0x40
+    field public static final int ROW_3_CENTER = 512; // 0x200
+    field public static final int ROW_3_LEFT = 256; // 0x100
+    field public static final int ROW_3_RIGHT = 1024; // 0x400
+    field public static final int ROW_ALL = 1911; // 0x777
+    field public static final int ROW_FIRST = 7; // 0x7
+    field public static final int ROW_SECOND = 112; // 0x70
+    field public static final int ROW_THIRD = 1792; // 0x700
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public interface CarZoneAreaIdConverter {
+    method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneUtils {
+    method public static com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int, int);
+    method public static androidx.car.app.hardware.common.CarZoneAreaIdConverter getZoneAreaIdConverter(int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class GlobalCarZoneAreaIdConverter implements androidx.car.app.hardware.common.CarZoneAreaIdConverter {
+    ctor public GlobalCarZoneAreaIdConverter();
+    method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class SeatCarZoneAreaIdConverter implements androidx.car.app.hardware.common.CarZoneAreaIdConverter {
+    ctor public SeatCarZoneAreaIdConverter();
+    method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+  }
+
+}
+
diff --git a/car/app/app-projected/api/1.4.0-beta01.txt b/car/app/app-projected/api/1.4.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/car/app/app-projected/api/1.4.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/car/app/app-projected/api/res-1.4.0-beta01.txt b/car/app/app-projected/api/res-1.4.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/car/app/app-projected/api/res-1.4.0-beta01.txt
diff --git a/car/app/app-projected/api/restricted_1.4.0-beta01.txt b/car/app/app-projected/api/restricted_1.4.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/car/app/app-projected/api/restricted_1.4.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/car/app/app-testing/api/1.4.0-beta01.txt b/car/app/app-testing/api/1.4.0-beta01.txt
new file mode 100644
index 0000000..57cf025
--- /dev/null
+++ b/car/app/app-testing/api/1.4.0-beta01.txt
@@ -0,0 +1,66 @@
+// Signature format: 4.0
+package androidx.car.app.testing {
+
+  public class FakeHost {
+    method public void performNotificationActionClick(android.app.PendingIntent);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void setMicrophoneInputData(java.io.InputStream);
+  }
+
+  public class ScreenController {
+    ctor public ScreenController(androidx.car.app.Screen);
+    method public androidx.car.app.Screen getScreen();
+    method public Object? getScreenResult();
+    method public java.util.List<androidx.car.app.model.Template!> getTemplatesReturned();
+    method public androidx.car.app.testing.ScreenController moveToState(androidx.lifecycle.Lifecycle.State);
+    method public void reset();
+  }
+
+  public class SessionController {
+    ctor public SessionController(androidx.car.app.Session, androidx.car.app.testing.TestCarContext, android.content.Intent);
+    method public androidx.car.app.Session getSession();
+    method public androidx.car.app.testing.SessionController moveToState(androidx.lifecycle.Lifecycle.State);
+  }
+
+  public class TestAppManager extends androidx.car.app.AppManager {
+    method public androidx.car.app.SurfaceCallback? getSurfaceCallback();
+    method public java.util.List<android.util.Pair<androidx.car.app.Screen!,androidx.car.app.model.Template!>!> getTemplatesReturned();
+    method public java.util.List<java.lang.CharSequence!> getToastsShown();
+    method public void reset();
+  }
+
+  public class TestCarContext extends androidx.car.app.CarContext {
+    method public static androidx.car.app.testing.TestCarContext createCarContext(android.content.Context);
+    method public androidx.car.app.testing.FakeHost getFakeHost();
+    method public androidx.car.app.testing.TestCarContext.PermissionRequestInfo? getLastPermissionRequestInfo();
+    method public java.util.List<android.content.Intent!> getStartCarAppIntents();
+    method public boolean hasCalledFinishCarApp();
+    method public void reset();
+  }
+
+  public static class TestCarContext.PermissionRequestInfo {
+    method public androidx.car.app.OnRequestPermissionsListener getListener();
+    method public java.util.List<java.lang.String!> getPermissionsRequested();
+  }
+
+  public class TestScreenManager extends androidx.car.app.ScreenManager {
+    method public java.util.List<androidx.car.app.Screen!> getScreensPushed();
+    method public java.util.List<androidx.car.app.Screen!> getScreensRemoved();
+    method public boolean hasScreens();
+    method public void reset();
+  }
+
+}
+
+package androidx.car.app.testing.navigation {
+
+  public class TestNavigationManager extends androidx.car.app.navigation.NavigationManager {
+    ctor public TestNavigationManager(androidx.car.app.testing.TestCarContext, androidx.car.app.HostDispatcher);
+    method public int getNavigationEndedCount();
+    method public androidx.car.app.navigation.NavigationManagerCallback? getNavigationManagerCallback();
+    method public int getNavigationStartedCount();
+    method public java.util.List<androidx.car.app.navigation.model.Trip!> getTripsSent();
+    method public void reset();
+  }
+
+}
+
diff --git a/car/app/app-testing/api/res-1.4.0-beta01.txt b/car/app/app-testing/api/res-1.4.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/car/app/app-testing/api/res-1.4.0-beta01.txt
diff --git a/car/app/app-testing/api/restricted_1.4.0-beta01.txt b/car/app/app-testing/api/restricted_1.4.0-beta01.txt
new file mode 100644
index 0000000..57cf025
--- /dev/null
+++ b/car/app/app-testing/api/restricted_1.4.0-beta01.txt
@@ -0,0 +1,66 @@
+// Signature format: 4.0
+package androidx.car.app.testing {
+
+  public class FakeHost {
+    method public void performNotificationActionClick(android.app.PendingIntent);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void setMicrophoneInputData(java.io.InputStream);
+  }
+
+  public class ScreenController {
+    ctor public ScreenController(androidx.car.app.Screen);
+    method public androidx.car.app.Screen getScreen();
+    method public Object? getScreenResult();
+    method public java.util.List<androidx.car.app.model.Template!> getTemplatesReturned();
+    method public androidx.car.app.testing.ScreenController moveToState(androidx.lifecycle.Lifecycle.State);
+    method public void reset();
+  }
+
+  public class SessionController {
+    ctor public SessionController(androidx.car.app.Session, androidx.car.app.testing.TestCarContext, android.content.Intent);
+    method public androidx.car.app.Session getSession();
+    method public androidx.car.app.testing.SessionController moveToState(androidx.lifecycle.Lifecycle.State);
+  }
+
+  public class TestAppManager extends androidx.car.app.AppManager {
+    method public androidx.car.app.SurfaceCallback? getSurfaceCallback();
+    method public java.util.List<android.util.Pair<androidx.car.app.Screen!,androidx.car.app.model.Template!>!> getTemplatesReturned();
+    method public java.util.List<java.lang.CharSequence!> getToastsShown();
+    method public void reset();
+  }
+
+  public class TestCarContext extends androidx.car.app.CarContext {
+    method public static androidx.car.app.testing.TestCarContext createCarContext(android.content.Context);
+    method public androidx.car.app.testing.FakeHost getFakeHost();
+    method public androidx.car.app.testing.TestCarContext.PermissionRequestInfo? getLastPermissionRequestInfo();
+    method public java.util.List<android.content.Intent!> getStartCarAppIntents();
+    method public boolean hasCalledFinishCarApp();
+    method public void reset();
+  }
+
+  public static class TestCarContext.PermissionRequestInfo {
+    method public androidx.car.app.OnRequestPermissionsListener getListener();
+    method public java.util.List<java.lang.String!> getPermissionsRequested();
+  }
+
+  public class TestScreenManager extends androidx.car.app.ScreenManager {
+    method public java.util.List<androidx.car.app.Screen!> getScreensPushed();
+    method public java.util.List<androidx.car.app.Screen!> getScreensRemoved();
+    method public boolean hasScreens();
+    method public void reset();
+  }
+
+}
+
+package androidx.car.app.testing.navigation {
+
+  public class TestNavigationManager extends androidx.car.app.navigation.NavigationManager {
+    ctor public TestNavigationManager(androidx.car.app.testing.TestCarContext, androidx.car.app.HostDispatcher);
+    method public int getNavigationEndedCount();
+    method public androidx.car.app.navigation.NavigationManagerCallback? getNavigationManagerCallback();
+    method public int getNavigationStartedCount();
+    method public java.util.List<androidx.car.app.navigation.model.Trip!> getTripsSent();
+    method public void reset();
+  }
+
+}
+
diff --git a/car/app/app/api/1.4.0-beta01.txt b/car/app/app/api/1.4.0-beta01.txt
new file mode 100644
index 0000000..73c12de
--- /dev/null
+++ b/car/app/app/api/1.4.0-beta01.txt
@@ -0,0 +1,2210 @@
+// Signature format: 4.0
+package androidx.car.app {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class AppInfo {
+    ctor @VisibleForTesting public AppInfo(int, int, String);
+    method public int getLatestCarAppApiLevel();
+    method public String getLibraryDisplayVersion();
+    method public int getMinCarAppApiLevel();
+    field public static final String MIN_API_LEVEL_METADATA_KEY = "androidx.car.app.minCarApiLevel";
+  }
+
+  public class AppManager implements androidx.car.app.managers.Manager {
+    method @androidx.car.app.annotations.RequiresCarApi(5) public void dismissAlert(int);
+    method public void invalidate();
+    method public void setSurfaceCallback(androidx.car.app.SurfaceCallback?);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public void showAlert(androidx.car.app.model.Alert);
+    method public void showToast(CharSequence, int);
+  }
+
+  public final class CarAppPermission {
+    method public static void checkHasLibraryPermission(android.content.Context, String);
+    method public static void checkHasPermission(android.content.Context, String);
+    field public static final String ACCESS_SURFACE = "androidx.car.app.ACCESS_SURFACE";
+    field public static final String MAP_TEMPLATES = "androidx.car.app.MAP_TEMPLATES";
+    field public static final String NAVIGATION_TEMPLATES = "androidx.car.app.NAVIGATION_TEMPLATES";
+  }
+
+  public abstract class CarAppService extends android.app.Service {
+    ctor public CarAppService();
+    method public abstract androidx.car.app.validation.HostValidator createHostValidator();
+    method @CallSuper public final void dump(java.io.FileDescriptor, java.io.PrintWriter, String![]?);
+    method @Deprecated public final androidx.car.app.Session? getCurrentSession();
+    method public final androidx.car.app.HostInfo? getHostInfo();
+    method public final androidx.car.app.Session? getSession(androidx.car.app.SessionInfo);
+    method @CallSuper public final android.os.IBinder onBind(android.content.Intent);
+    method public androidx.car.app.Session onCreateSession();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.Session onCreateSession(androidx.car.app.SessionInfo);
+    method public final boolean onUnbind(android.content.Intent);
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_CALLING_APP = "androidx.car.app.category.CALLING";
+    field @Deprecated public static final String CATEGORY_CHARGING_APP = "androidx.car.app.category.CHARGING";
+    field @androidx.car.app.annotations.RequiresCarApi(6) public static final String CATEGORY_FEATURE_CLUSTER = "androidx.car.app.category.FEATURE_CLUSTER";
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_IOT_APP = "androidx.car.app.category.IOT";
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_MESSAGING_APP = "androidx.car.app.category.MESSAGING";
+    field public static final String CATEGORY_NAVIGATION_APP = "androidx.car.app.category.NAVIGATION";
+    field @Deprecated public static final String CATEGORY_PARKING_APP = "androidx.car.app.category.PARKING";
+    field public static final String CATEGORY_POI_APP = "androidx.car.app.category.POI";
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_SETTINGS_APP = "androidx.car.app.category.SETTINGS";
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_WEATHER_APP = "androidx.car.app.category.WEATHER";
+    field public static final String SERVICE_INTERFACE = "androidx.car.app.CarAppService";
+  }
+
+  public class CarContext extends android.content.ContextWrapper {
+    method public void finishCarApp();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public android.content.ComponentName? getCallingComponent();
+    method public int getCarAppApiLevel();
+    method public <T> T getCarService(Class<T!>);
+    method public Object getCarService(String);
+    method public String getCarServiceName(Class<?>);
+    method public androidx.car.app.HostInfo? getHostInfo();
+    method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+    method public boolean isDarkMode();
+    method public void requestPermissions(java.util.List<java.lang.String!>, androidx.car.app.OnRequestPermissionsListener);
+    method public void requestPermissions(java.util.List<java.lang.String!>, java.util.concurrent.Executor, androidx.car.app.OnRequestPermissionsListener);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public void setCarAppResult(int, android.content.Intent?);
+    method public void startCarApp(android.content.Intent);
+    method @Deprecated public static void startCarApp(android.content.Intent, android.content.Intent);
+    field public static final String ACTION_NAVIGATE = "androidx.car.app.action.NAVIGATE";
+    field public static final String APP_SERVICE = "app";
+    field public static final String CAR_SERVICE = "car";
+    field @androidx.car.app.annotations.RequiresCarApi(2) public static final String CONSTRAINT_SERVICE = "constraints";
+    field public static final String EXTRA_START_CAR_APP_BINDER_KEY = "androidx.car.app.extra.START_CAR_APP_BINDER_KEY";
+    field @androidx.car.app.annotations.RequiresCarApi(3) public static final String HARDWARE_SERVICE = "hardware";
+    field public static final String NAVIGATION_SERVICE = "navigation";
+    field public static final String SCREEN_SERVICE = "screen";
+    field public static final String SUGGESTION_SERVICE = "suggestion";
+  }
+
+  public final class CarToast {
+    method public static androidx.car.app.CarToast makeText(androidx.car.app.CarContext, @StringRes int, int);
+    method public static androidx.car.app.CarToast makeText(androidx.car.app.CarContext, CharSequence, int);
+    method public void setDuration(int);
+    method public void setText(@StringRes int);
+    method public void setText(CharSequence);
+    method public void show();
+    field public static final int LENGTH_LONG = 1; // 0x1
+    field public static final int LENGTH_SHORT = 0; // 0x0
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class FailureResponse {
+    ctor public FailureResponse(Throwable);
+    method public int getErrorType();
+    method public String getStackTrace();
+    field public static final int BUNDLER_EXCEPTION = 1; // 0x1
+    field public static final int ILLEGAL_STATE_EXCEPTION = 2; // 0x2
+    field public static final int INVALID_PARAMETER_EXCEPTION = 3; // 0x3
+    field public static final int REMOTE_EXCEPTION = 6; // 0x6
+    field public static final int RUNTIME_EXCEPTION = 5; // 0x5
+    field public static final int SECURITY_EXCEPTION = 4; // 0x4
+    field public static final int UNKNOWN_ERROR = 0; // 0x0
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class HandshakeInfo {
+    ctor public HandshakeInfo(String, int);
+    method public int getHostCarAppApiLevel();
+    method public String getHostPackageName();
+  }
+
+  public final class HostException extends java.lang.RuntimeException {
+    ctor public HostException(String);
+    ctor public HostException(String, Throwable);
+    ctor public HostException(Throwable);
+  }
+
+  public final class HostInfo {
+    ctor public HostInfo(String, int);
+    method public String getPackageName();
+    method public int getUid();
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnDoneCallback {
+    method public default void onFailure(androidx.car.app.serialization.Bundleable);
+    method public default void onSuccess(androidx.car.app.serialization.Bundleable?);
+  }
+
+  public interface OnRequestPermissionsListener {
+    method public void onRequestPermissionsResult(java.util.List<java.lang.String!>, java.util.List<java.lang.String!>);
+  }
+
+  public interface OnScreenResultListener {
+    method public void onScreenResult(Object?);
+  }
+
+  public abstract class Screen implements androidx.lifecycle.LifecycleOwner {
+    ctor protected Screen(androidx.car.app.CarContext);
+    method public final void finish();
+    method public final androidx.car.app.CarContext getCarContext();
+    method public final androidx.lifecycle.Lifecycle getLifecycle();
+    method public String? getMarker();
+    method public final androidx.car.app.ScreenManager getScreenManager();
+    method public final void invalidate();
+    method public abstract androidx.car.app.model.Template onGetTemplate();
+    method public void setMarker(String?);
+    method public void setResult(Object?);
+  }
+
+  @MainThread public class ScreenManager implements androidx.car.app.managers.Manager {
+    method public java.util.Collection<androidx.car.app.Screen!> getScreenStack();
+    method public int getStackSize();
+    method public androidx.car.app.Screen getTop();
+    method public void pop();
+    method public void popTo(String);
+    method public void popToRoot();
+    method public void push(androidx.car.app.Screen);
+    method public void pushForResult(androidx.car.app.Screen, androidx.car.app.OnScreenResultListener);
+    method public void remove(androidx.car.app.Screen);
+  }
+
+  public abstract class Session implements androidx.lifecycle.LifecycleOwner {
+    ctor public Session();
+    method public final androidx.car.app.CarContext getCarContext();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method public void onCarConfigurationChanged(android.content.res.Configuration);
+    method public abstract androidx.car.app.Screen onCreateScreen(android.content.Intent);
+    method public void onNewIntent(android.content.Intent);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class SessionInfo {
+    ctor public SessionInfo(int, String);
+    method public int getDisplayType();
+    method public String getSessionId();
+    method public java.util.Set<java.lang.Class<? extends androidx.car.app.model.Template>!>? getSupportedTemplates(int);
+    field public static final androidx.car.app.SessionInfo DEFAULT_SESSION_INFO;
+    field public static final int DISPLAY_TYPE_CLUSTER = 1; // 0x1
+    field public static final int DISPLAY_TYPE_MAIN = 0; // 0x0
+  }
+
+  public class SessionInfoIntentEncoder {
+    method public static boolean containsSessionInfo(android.content.Intent);
+    method public static androidx.car.app.SessionInfo decode(android.content.Intent);
+    method public static void encode(androidx.car.app.SessionInfo, android.content.Intent);
+  }
+
+  public interface SurfaceCallback {
+    method @androidx.car.app.annotations.RequiresCarApi(5) public default void onClick(float, float);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public default void onFling(float, float);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public default void onScale(float, float, float);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public default void onScroll(float, float);
+    method public default void onStableAreaChanged(android.graphics.Rect);
+    method public default void onSurfaceAvailable(androidx.car.app.SurfaceContainer);
+    method public default void onSurfaceDestroyed(androidx.car.app.SurfaceContainer);
+    method public default void onVisibleAreaChanged(android.graphics.Rect);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SurfaceContainer {
+    ctor public SurfaceContainer(android.view.Surface?, int, int, int);
+    method public int getDpi();
+    method public int getHeight();
+    method public android.view.Surface? getSurface();
+    method public int getWidth();
+  }
+
+}
+
+package androidx.car.app.annotations {
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.PARAMETER}) public @interface CarProtocol {
+  }
+
+  @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface ExperimentalCarApi {
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface RequiresCarApi {
+    method public abstract int value();
+  }
+
+}
+
+package androidx.car.app.connection {
+
+  public final class CarConnection {
+    ctor @MainThread public CarConnection(android.content.Context);
+    method public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
+    field public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
+    field public static final String CAR_CONNECTION_STATE = "CarConnectionState";
+    field public static final int CONNECTION_TYPE_NATIVE = 1; // 0x1
+    field public static final int CONNECTION_TYPE_NOT_CONNECTED = 0; // 0x0
+    field public static final int CONNECTION_TYPE_PROJECTION = 2; // 0x2
+  }
+
+}
+
+package androidx.car.app.constraints {
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public class ConstraintManager implements androidx.car.app.managers.Manager {
+    method public int getContentLimit(int);
+    method @androidx.car.app.annotations.RequiresCarApi(6) public boolean isAppDrivenRefreshEnabled();
+    field public static final int CONTENT_LIMIT_TYPE_GRID = 1; // 0x1
+    field public static final int CONTENT_LIMIT_TYPE_LIST = 0; // 0x0
+    field public static final int CONTENT_LIMIT_TYPE_PANE = 4; // 0x4
+    field public static final int CONTENT_LIMIT_TYPE_PLACE_LIST = 2; // 0x2
+    field public static final int CONTENT_LIMIT_TYPE_ROUTE_LIST = 3; // 0x3
+  }
+
+}
+
+package androidx.car.app.hardware {
+
+  @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarHardwareManager extends androidx.car.app.managers.Manager {
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public default androidx.car.app.hardware.climate.CarClimate getCarClimate();
+    method public default androidx.car.app.hardware.info.CarInfo getCarInfo();
+    method public default androidx.car.app.hardware.info.CarSensors getCarSensors();
+  }
+
+}
+
+package androidx.car.app.hardware.climate {
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CabinTemperatureProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Float!,java.lang.Float!>!> getCarZoneSetsToCabinCelsiusTemperatureRanges();
+    method public float getCelsiusSupportedIncrement();
+    method public float getFahrenheitSupportedIncrement();
+    method public android.util.Pair<java.lang.Float!,java.lang.Float!> getSupportedMinMaxCelsiusRange();
+    method public android.util.Pair<java.lang.Float!,java.lang.Float!> getSupportedMinMaxFahrenheitRange();
+    method public boolean hasCarZoneSetsToCabinCelsiusTemperatureRanges();
+    method public boolean hasCelsiusSupportedIncrement();
+    method public boolean hasFahrenheitSupportedIncrement();
+    method public boolean hasSupportedMinMaxCelsiusRange();
+    method public boolean hasSupportedMinMaxFahrenheitRange();
+  }
+
+  public static final class CabinTemperatureProfile.Builder {
+    ctor public CabinTemperatureProfile.Builder();
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile build();
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setCarZoneSetsToCabinCelsiusTemperatureRanges(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Float!,java.lang.Float!>!>);
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setCelsiusSupportedIncrement(float);
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setFahrenheitSupportedIncrement(float);
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setSupportedMinMaxCelsiusRange(android.util.Pair<java.lang.Float!,java.lang.Float!>);
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setSupportedMinMaxFahrenheitRange(android.util.Pair<java.lang.Float!,java.lang.Float!>);
+  }
+
+  @SuppressCompatibility @MainThread @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimate {
+    method public void fetchClimateProfile(java.util.concurrent.Executor, androidx.car.app.hardware.climate.ClimateProfileRequest, androidx.car.app.hardware.climate.CarClimateProfileCallback);
+    method public void registerClimateStateCallback(java.util.concurrent.Executor, androidx.car.app.hardware.climate.RegisterClimateStateRequest, androidx.car.app.hardware.climate.CarClimateStateCallback);
+    method public <E> void setClimateState(java.util.concurrent.Executor, androidx.car.app.hardware.climate.ClimateStateRequest<E!>, androidx.car.app.hardware.common.CarSetOperationStatusCallback);
+    method public void unregisterClimateStateCallback(androidx.car.app.hardware.climate.CarClimateStateCallback);
+  }
+
+  @SuppressCompatibility @MainThread @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class CarClimateFeature {
+    method public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+    method public int getFeature();
+  }
+
+  public static final class CarClimateFeature.Builder {
+    ctor public CarClimateFeature.Builder(int);
+    method public androidx.car.app.hardware.climate.CarClimateFeature.Builder addCarZones(androidx.car.app.hardware.common.CarZone!...);
+    method public androidx.car.app.hardware.climate.CarClimateFeature build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimateProfileCallback {
+    method public default void onCabinTemperatureProfileAvailable(androidx.car.app.hardware.climate.CabinTemperatureProfile);
+    method public default void onCarZoneMappingInfoProfileAvailable(androidx.car.app.hardware.climate.CarZoneMappingInfoProfile);
+    method public default void onDefrosterProfileAvailable(androidx.car.app.hardware.climate.DefrosterProfile);
+    method public default void onElectricDefrosterProfileAvailable(androidx.car.app.hardware.climate.ElectricDefrosterProfile);
+    method public default void onFanDirectionProfileAvailable(androidx.car.app.hardware.climate.FanDirectionProfile);
+    method public default void onFanSpeedLevelProfileAvailable(androidx.car.app.hardware.climate.FanSpeedLevelProfile);
+    method public default void onHvacAcProfileAvailable(androidx.car.app.hardware.climate.HvacAcProfile);
+    method public default void onHvacAutoModeProfileAvailable(androidx.car.app.hardware.climate.HvacAutoModeProfile);
+    method public default void onHvacAutoRecirculationProfileAvailable(androidx.car.app.hardware.climate.HvacAutoRecirculationProfile);
+    method public default void onHvacDualModeProfileAvailable(androidx.car.app.hardware.climate.HvacDualModeProfile);
+    method public default void onHvacMaxAcModeProfileAvailable(androidx.car.app.hardware.climate.HvacMaxAcModeProfile);
+    method public default void onHvacPowerProfileAvailable(androidx.car.app.hardware.climate.HvacPowerProfile);
+    method public default void onHvacRecirculationProfileAvailable(androidx.car.app.hardware.climate.HvacRecirculationProfile);
+    method public default void onMaxDefrosterProfileAvailable(androidx.car.app.hardware.climate.MaxDefrosterProfile);
+    method public default void onSeatTemperatureLevelProfileAvailable(androidx.car.app.hardware.climate.SeatTemperatureProfile);
+    method public default void onSeatVentilationLevelProfileAvailable(androidx.car.app.hardware.climate.SeatVentilationProfile);
+    method public default void onSteeringWheelHeatProfileAvailable(androidx.car.app.hardware.climate.SteeringWheelHeatProfile);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimateStateCallback {
+    method public default void onCabinTemperatureStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method public default void onDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onElectricDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onFanDirectionStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public default void onFanSpeedLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public default void onHvacAcStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacAutoModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacAutoRecirculationStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacDualModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacMaxAcModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacPowerStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacRecirculationStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onMaxDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onSeatTemperatureLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public default void onSeatVentilationLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public default void onSteeringWheelHeatStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneMappingInfoProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class CarZoneMappingInfoProfile.Builder {
+    ctor public CarZoneMappingInfoProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.CarZoneMappingInfoProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class ClimateProfileRequest {
+    method public java.util.Set<java.lang.Integer!> getAllClimateProfiles();
+    method public java.util.List<androidx.car.app.hardware.climate.CarClimateFeature!> getClimateProfileFeatures();
+    field public static final int FEATURE_CABIN_TEMPERATURE = 4; // 0x4
+    field public static final int FEATURE_CAR_ZONE_MAPPING = 17; // 0x11
+    field public static final int FEATURE_FAN_DIRECTION = 6; // 0x6
+    field public static final int FEATURE_FAN_SPEED = 5; // 0x5
+    field public static final int FEATURE_HVAC_AC = 2; // 0x2
+    field public static final int FEATURE_HVAC_AUTO_MODE = 12; // 0xc
+    field public static final int FEATURE_HVAC_AUTO_RECIRCULATION = 11; // 0xb
+    field public static final int FEATURE_HVAC_DEFROSTER = 14; // 0xe
+    field public static final int FEATURE_HVAC_DUAL_MODE = 13; // 0xd
+    field public static final int FEATURE_HVAC_ELECTRIC_DEFROSTER = 16; // 0x10
+    field public static final int FEATURE_HVAC_MAX_AC = 3; // 0x3
+    field public static final int FEATURE_HVAC_MAX_DEFROSTER = 15; // 0xf
+    field public static final int FEATURE_HVAC_POWER = 1; // 0x1
+    field public static final int FEATURE_HVAC_RECIRCULATION = 10; // 0xa
+    field public static final int FEATURE_SEAT_TEMPERATURE_LEVEL = 7; // 0x7
+    field public static final int FEATURE_SEAT_VENTILATION_LEVEL = 8; // 0x8
+    field public static final int FEATURE_STEERING_WHEEL_HEAT = 9; // 0x9
+  }
+
+  public static final class ClimateProfileRequest.Builder {
+    ctor public ClimateProfileRequest.Builder();
+    method public androidx.car.app.hardware.climate.ClimateProfileRequest.Builder addClimateProfileFeatures(androidx.car.app.hardware.climate.CarClimateFeature!...);
+    method public androidx.car.app.hardware.climate.ClimateProfileRequest build();
+    method public androidx.car.app.hardware.climate.ClimateProfileRequest.Builder setAllClimateProfiles();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class ClimateStateRequest<T> {
+    method public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+    method public int getRequestedFeature();
+    method public T getRequestedValue();
+  }
+
+  public static final class ClimateStateRequest.Builder<T> {
+    ctor public ClimateStateRequest.Builder(int, T!);
+    method public androidx.car.app.hardware.climate.ClimateStateRequest.Builder<T!> addCarZones(androidx.car.app.hardware.common.CarZone);
+    method public androidx.car.app.hardware.climate.ClimateStateRequest<T!> build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class DefrosterProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class DefrosterProfile.Builder {
+    ctor public DefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.DefrosterProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class ElectricDefrosterProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class ElectricDefrosterProfile.Builder {
+    ctor public ElectricDefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.ElectricDefrosterProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class FanDirectionProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,java.util.Set<java.lang.Integer!>!> getCarZoneSetsToFanDirectionValues();
+  }
+
+  public static final class FanDirectionProfile.Builder {
+    ctor public FanDirectionProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,java.util.Set<java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.FanDirectionProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class FanSpeedLevelProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToFanSpeedLevelRanges();
+  }
+
+  public static final class FanSpeedLevelProfile.Builder {
+    ctor public FanSpeedLevelProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.FanSpeedLevelProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAcProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacAcProfile.Builder {
+    ctor public HvacAcProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacAcProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAutoModeProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacAutoModeProfile.Builder {
+    ctor public HvacAutoModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacAutoModeProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAutoRecirculationProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacAutoRecirculationProfile.Builder {
+    ctor public HvacAutoRecirculationProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacAutoRecirculationProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacDualModeProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacDualModeProfile.Builder {
+    ctor public HvacDualModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacDualModeProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacMaxAcModeProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacMaxAcModeProfile.Builder {
+    ctor public HvacMaxAcModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacMaxAcModeProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacPowerProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacPowerProfile.Builder {
+    ctor public HvacPowerProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacPowerProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacRecirculationProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZones();
+  }
+
+  public static final class HvacRecirculationProfile.Builder {
+    ctor public HvacRecirculationProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacRecirculationProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class MaxDefrosterProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class MaxDefrosterProfile.Builder {
+    ctor public MaxDefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.MaxDefrosterProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class RegisterClimateStateRequest {
+    method public java.util.List<androidx.car.app.hardware.climate.CarClimateFeature!> getClimateRegisterFeatures();
+  }
+
+  public static final class RegisterClimateStateRequest.Builder {
+    ctor public RegisterClimateStateRequest.Builder(boolean);
+    method public androidx.car.app.hardware.climate.RegisterClimateStateRequest.Builder addClimateRegisterFeatures(androidx.car.app.hardware.climate.CarClimateFeature!...);
+    method public androidx.car.app.hardware.climate.RegisterClimateStateRequest build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SeatTemperatureProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSeatTemperatureValues();
+  }
+
+  public static final class SeatTemperatureProfile.Builder {
+    ctor public SeatTemperatureProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.SeatTemperatureProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SeatVentilationProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSeatVentilationValues();
+  }
+
+  public static final class SeatVentilationProfile.Builder {
+    ctor public SeatVentilationProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.SeatVentilationProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SteeringWheelHeatProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSteeringWheelHeatValues();
+  }
+
+  public static final class SteeringWheelHeatProfile.Builder {
+    ctor public SteeringWheelHeatProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.SteeringWheelHeatProfile build();
+  }
+
+}
+
+package androidx.car.app.hardware.common {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarSetOperationStatusCallback {
+    method public default void onSetCarClimateStateCabinTemperature(int);
+    method public default void onSetCarClimateStateDefroster(int);
+    method public default void onSetCarClimateStateElectricDefroster(int);
+    method public default void onSetCarClimateStateFanDirection(int);
+    method public default void onSetCarClimateStateFanSpeedLevel(int);
+    method public default void onSetCarClimateStateHvacAc(int);
+    method public default void onSetCarClimateStateHvacAutoMode(int);
+    method public default void onSetCarClimateStateHvacAutoRecirculation(int);
+    method public default void onSetCarClimateStateHvacDualMode(int);
+    method public default void onSetCarClimateStateHvacMaxAcMode(int);
+    method public default void onSetCarClimateStateHvacPower(int);
+    method public default void onSetCarClimateStateHvacRecirculation(int);
+    method public default void onSetCarClimateStateMaxDefroster(int);
+    method public default void onSetCarClimateStateSeatTemperatureLevel(int);
+    method public default void onSetCarClimateStateSeatVentilationLevel(int);
+    method public default void onSetCarClimateStateSteeringWheelHeat(int);
+    method public static String toString(int);
+    field public static final int OPERATION_STATUS_FEATURE_SETTING_NOT_ALLOWED = 4; // 0x4
+    field public static final int OPERATION_STATUS_FEATURE_TEMPORARILY_UNAVAILABLE = 3; // 0x3
+    field public static final int OPERATION_STATUS_FEATURE_UNIMPLEMENTED = 1; // 0x1
+    field public static final int OPERATION_STATUS_FEATURE_UNSUPPORTED = 2; // 0x2
+    field public static final int OPERATION_STATUS_ILLEGAL_CAR_HARDWARE_STATE = 7; // 0x7
+    field public static final int OPERATION_STATUS_INSUFFICIENT_PERMISSION = 6; // 0x6
+    field public static final int OPERATION_STATUS_SUCCESS = 0; // 0x0
+    field public static final int OPERATION_STATUS_UNSUPPORTED_VALUE = 5; // 0x5
+    field public static final int OPERATION_STATUS_UPDATE_TIMEOUT = 8; // 0x8
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarUnit {
+    method public static String toString(int);
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int IMPERIAL_GALLON = 204; // 0xcc
+    field public static final int KILOMETER = 3; // 0x3
+    field public static final int KILOMETERS_PER_HOUR = 102; // 0x66
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int LITER = 202; // 0xca
+    field public static final int METER = 2; // 0x2
+    field public static final int METERS_PER_SEC = 101; // 0x65
+    field public static final int MILE = 4; // 0x4
+    field public static final int MILES_PER_HOUR = 103; // 0x67
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int MILLILITER = 201; // 0xc9
+    field public static final int MILLIMETER = 1; // 0x1
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int US_GALLON = 203; // 0xcb
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarValue<T> {
+    ctor public CarValue(T?, long, int);
+    ctor @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public CarValue(T?, long, int, java.util.List<androidx.car.app.hardware.common.CarZone!>);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+    method public int getStatus();
+    method public long getTimestampMillis();
+    method public T? getValue();
+    field public static final int STATUS_SUCCESS = 1; // 0x1
+    field public static final int STATUS_UNAVAILABLE = 3; // 0x3
+    field public static final int STATUS_UNIMPLEMENTED = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class CarZone {
+    method public int getColumn();
+    method public int getRow();
+    field public static final int CAR_ZONE_COLUMN_ALL = 16; // 0x10
+    field public static final int CAR_ZONE_COLUMN_CENTER = 48; // 0x30
+    field public static final int CAR_ZONE_COLUMN_DRIVER = 80; // 0x50
+    field public static final int CAR_ZONE_COLUMN_LEFT = 32; // 0x20
+    field public static final int CAR_ZONE_COLUMN_PASSENGER = 96; // 0x60
+    field public static final int CAR_ZONE_COLUMN_RIGHT = 64; // 0x40
+    field public static final androidx.car.app.hardware.common.CarZone CAR_ZONE_GLOBAL;
+    field public static final int CAR_ZONE_ROW_ALL = 0; // 0x0
+    field public static final int CAR_ZONE_ROW_EXCLUDE_FIRST = 4; // 0x4
+    field public static final int CAR_ZONE_ROW_FIRST = 1; // 0x1
+    field public static final int CAR_ZONE_ROW_SECOND = 2; // 0x2
+    field public static final int CAR_ZONE_ROW_THIRD = 3; // 0x3
+  }
+
+  public static final class CarZone.Builder {
+    ctor public CarZone.Builder();
+    method public androidx.car.app.hardware.common.CarZone build();
+    method public androidx.car.app.hardware.common.CarZone.Builder setColumn(int);
+    method public androidx.car.app.hardware.common.CarZone.Builder setRow(int);
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public interface OnCarDataAvailableListener<T> {
+    method public void onCarDataAvailable(T);
+  }
+
+}
+
+package androidx.car.app.hardware.info {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Accelerometer {
+    ctor public Accelerometer(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getForces();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarHardwareLocation {
+    ctor public CarHardwareLocation(androidx.car.app.hardware.common.CarValue<android.location.Location!>);
+    method public androidx.car.app.hardware.common.CarValue<android.location.Location!> getLocation();
+  }
+
+  @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarInfo {
+    method public void addEnergyLevelListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyLevel!>);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void addEvStatusListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EvStatus!>);
+    method public void addMileageListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Mileage!>);
+    method public void addSpeedListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Speed!>);
+    method public void addTollListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.TollCard!>);
+    method public void fetchEnergyProfile(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyProfile!>);
+    method public void fetchModel(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Model!>);
+    method public void removeEnergyLevelListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyLevel!>);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void removeEvStatusListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EvStatus!>);
+    method public void removeMileageListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Mileage!>);
+    method public void removeSpeedListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Speed!>);
+    method public void removeTollListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.TollCard!>);
+  }
+
+  @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarSensors {
+    method public void addAccelerometerListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Accelerometer!>);
+    method public void addCarHardwareLocationListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.CarHardwareLocation!>);
+    method public void addCompassListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Compass!>);
+    method public void addGyroscopeListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Gyroscope!>);
+    method public void removeAccelerometerListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Accelerometer!>);
+    method public void removeCarHardwareLocationListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.CarHardwareLocation!>);
+    method public void removeCompassListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Compass!>);
+    method public void removeGyroscopeListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Gyroscope!>);
+    field public static final int UPDATE_RATE_FASTEST = 3; // 0x3
+    field public static final int UPDATE_RATE_NORMAL = 1; // 0x1
+    field public static final int UPDATE_RATE_UI = 2; // 0x2
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Compass {
+    ctor public Compass(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getOrientations();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyLevel {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getBatteryPercent();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getDistanceDisplayUnit();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEnergyIsLow();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getFuelPercent();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getFuelVolumeDisplayUnit();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getRangeRemainingMeters();
+  }
+
+  public static final class EnergyLevel.Builder {
+    ctor public EnergyLevel.Builder();
+    method public androidx.car.app.hardware.info.EnergyLevel build();
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setBatteryPercent(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setDistanceDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setEnergyIsLow(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setFuelPercent(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.hardware.info.EnergyLevel.Builder setFuelVolumeDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setRangeRemainingMeters(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyProfile {
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getEvConnectorTypes();
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getFuelTypes();
+    field public static final int EVCONNECTOR_TYPE_CHADEMO = 3; // 0x3
+    field public static final int EVCONNECTOR_TYPE_COMBO_1 = 4; // 0x4
+    field public static final int EVCONNECTOR_TYPE_COMBO_2 = 5; // 0x5
+    field public static final int EVCONNECTOR_TYPE_GBT = 9; // 0x9
+    field public static final int EVCONNECTOR_TYPE_GBT_DC = 10; // 0xa
+    field public static final int EVCONNECTOR_TYPE_J1772 = 1; // 0x1
+    field public static final int EVCONNECTOR_TYPE_MENNEKES = 2; // 0x2
+    field public static final int EVCONNECTOR_TYPE_OTHER = 101; // 0x65
+    field public static final int EVCONNECTOR_TYPE_SCAME = 11; // 0xb
+    field public static final int EVCONNECTOR_TYPE_TESLA_HPWC = 7; // 0x7
+    field public static final int EVCONNECTOR_TYPE_TESLA_ROADSTER = 6; // 0x6
+    field public static final int EVCONNECTOR_TYPE_TESLA_SUPERCHARGER = 8; // 0x8
+    field public static final int EVCONNECTOR_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int FUEL_TYPE_BIODIESEL = 5; // 0x5
+    field public static final int FUEL_TYPE_CNG = 8; // 0x8
+    field public static final int FUEL_TYPE_DIESEL_1 = 3; // 0x3
+    field public static final int FUEL_TYPE_DIESEL_2 = 4; // 0x4
+    field public static final int FUEL_TYPE_E85 = 6; // 0x6
+    field public static final int FUEL_TYPE_ELECTRIC = 10; // 0xa
+    field public static final int FUEL_TYPE_HYDROGEN = 11; // 0xb
+    field public static final int FUEL_TYPE_LEADED = 2; // 0x2
+    field public static final int FUEL_TYPE_LNG = 9; // 0x9
+    field public static final int FUEL_TYPE_LPG = 7; // 0x7
+    field public static final int FUEL_TYPE_OTHER = 12; // 0xc
+    field public static final int FUEL_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int FUEL_TYPE_UNLEADED = 1; // 0x1
+  }
+
+  public static final class EnergyProfile.Builder {
+    ctor public EnergyProfile.Builder();
+    method public androidx.car.app.hardware.info.EnergyProfile build();
+    method public androidx.car.app.hardware.info.EnergyProfile.Builder setEvConnectorTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.info.EnergyProfile.Builder setFuelTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi public class EvStatus {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEvChargePortConnected();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEvChargePortOpen();
+  }
+
+  public static final class EvStatus.Builder {
+    ctor public EvStatus.Builder();
+    method public androidx.car.app.hardware.info.EvStatus build();
+    method public androidx.car.app.hardware.info.EvStatus.Builder setEvChargePortConnected(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public androidx.car.app.hardware.info.EvStatus.Builder setEvChargePortOpen(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Gyroscope {
+    ctor public Gyroscope(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getRotations();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Mileage {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getDistanceDisplayUnit();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getOdometerMeters();
+  }
+
+  public static final class Mileage.Builder {
+    ctor public Mileage.Builder();
+    method public androidx.car.app.hardware.info.Mileage build();
+    method public androidx.car.app.hardware.info.Mileage.Builder setDistanceDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public androidx.car.app.hardware.info.Mileage.Builder setOdometerMeters(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Model {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.String!> getManufacturer();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.String!> getName();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getYear();
+  }
+
+  public static final class Model.Builder {
+    ctor public Model.Builder();
+    method public androidx.car.app.hardware.info.Model build();
+    method public androidx.car.app.hardware.info.Model.Builder setManufacturer(androidx.car.app.hardware.common.CarValue<java.lang.String!>);
+    method public androidx.car.app.hardware.info.Model.Builder setName(androidx.car.app.hardware.common.CarValue<java.lang.String!>);
+    method public androidx.car.app.hardware.info.Model.Builder setYear(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Speed {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getDisplaySpeedMetersPerSecond();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getRawSpeedMetersPerSecond();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getSpeedDisplayUnit();
+  }
+
+  public static final class Speed.Builder {
+    ctor public Speed.Builder();
+    method public androidx.car.app.hardware.info.Speed build();
+    method public androidx.car.app.hardware.info.Speed.Builder setDisplaySpeedMetersPerSecond(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method public androidx.car.app.hardware.info.Speed.Builder setRawSpeedMetersPerSecond(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method public androidx.car.app.hardware.info.Speed.Builder setSpeedDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class TollCard {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getCardState();
+    field public static final int TOLLCARD_STATE_INVALID = 2; // 0x2
+    field public static final int TOLLCARD_STATE_NOT_INSERTED = 3; // 0x3
+    field public static final int TOLLCARD_STATE_UNKNOWN = 0; // 0x0
+    field public static final int TOLLCARD_STATE_VALID = 1; // 0x1
+  }
+
+  public static final class TollCard.Builder {
+    ctor public TollCard.Builder();
+    method public androidx.car.app.hardware.info.TollCard build();
+    method public androidx.car.app.hardware.info.TollCard.Builder setCardState(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+  }
+
+}
+
+package androidx.car.app.managers {
+
+  public interface Manager {
+  }
+
+}
+
+package androidx.car.app.media {
+
+  @androidx.car.app.annotations.RequiresCarApi(5) public interface CarAudioCallback {
+    method public void onStopRecording();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public class CarAudioCallbackDelegate {
+    method public void onStopRecording();
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(5) public abstract class CarAudioRecord {
+    method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public static androidx.car.app.media.CarAudioRecord create(androidx.car.app.CarContext);
+    method public int read(byte[], int, int);
+    method public void startRecording();
+    method public void stopRecording();
+    field public static final int AUDIO_CONTENT_BUFFER_SIZE = 512; // 0x200
+    field public static final String AUDIO_CONTENT_MIME = "audio/l16";
+    field public static final int AUDIO_CONTENT_SAMPLING_RATE = 16000; // 0x3e80
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class OpenMicrophoneRequest {
+    method public androidx.car.app.media.CarAudioCallbackDelegate getCarAudioCallbackDelegate();
+  }
+
+  public static final class OpenMicrophoneRequest.Builder {
+    ctor public OpenMicrophoneRequest.Builder(androidx.car.app.media.CarAudioCallback);
+    method public androidx.car.app.media.OpenMicrophoneRequest build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class OpenMicrophoneResponse {
+    method public androidx.car.app.media.CarAudioCallbackDelegate getCarAudioCallback();
+    method public java.io.InputStream getCarMicrophoneInputStream();
+  }
+
+  public static final class OpenMicrophoneResponse.Builder {
+    ctor public OpenMicrophoneResponse.Builder(androidx.car.app.media.CarAudioCallback);
+    method public androidx.car.app.media.OpenMicrophoneResponse build();
+    method public androidx.car.app.media.OpenMicrophoneResponse.Builder setCarMicrophoneDescriptor(android.os.ParcelFileDescriptor);
+  }
+
+}
+
+package androidx.car.app.mediaextensions {
+
+  public final class MetadataExtras {
+    field public static final String KEY_CONTENT_FORMAT_DARK_MODE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_DARK_MODE_LARGE_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_DARK_MODE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_DARK_MODE_SMALL_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_LIGHT_MODE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_LIGHT_MODE_LARGE_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_LIGHT_MODE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_LIGHT_MODE_SMALL_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI";
+    field public static final String KEY_DESCRIPTION_LINK_MEDIA_ID = "androidx.car.app.mediaextensions.KEY_DESCRIPTION_LINK_MEDIA_ID";
+    field public static final String KEY_IMMERSIVE_AUDIO = "androidx.car.app.mediaextensions.KEY_IMMERSIVE_AUDIO";
+    field public static final String KEY_SUBTITLE_LINK_MEDIA_ID = "androidx.car.app.mediaextensions.KEY_SUBTITLE_LINK_MEDIA_ID";
+  }
+
+}
+
+package androidx.car.app.messaging {
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class MessagingServiceConstants {
+    field public static final String ACTION_HANDLE_CAR_MESSAGING = "androidx.car.app.messaging.action.HANDLE_CAR_MESSAGING";
+  }
+
+}
+
+package androidx.car.app.messaging.model {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class CarMessage {
+    method public androidx.car.app.model.CarText? getBody();
+    method public String? getMultimediaMimeType();
+    method public android.net.Uri? getMultimediaUri();
+    method public long getReceivedTimeEpochMillis();
+    method public androidx.core.app.Person? getSender();
+    method public boolean isRead();
+  }
+
+  public static final class CarMessage.Builder {
+    ctor public CarMessage.Builder();
+    method public androidx.car.app.messaging.model.CarMessage build();
+    method public androidx.car.app.messaging.model.CarMessage.Builder setBody(androidx.car.app.model.CarText?);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setMultimediaMimeType(String?);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setMultimediaUri(android.net.Uri?);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setRead(boolean);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setReceivedTimeEpochMillis(long);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setSender(androidx.core.app.Person?);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi public interface ConversationCallback {
+    method public void onMarkAsRead();
+    method public void onTextReply(String);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public interface ConversationCallbackDelegate {
+    method public void sendMarkAsRead(androidx.car.app.OnDoneCallback);
+    method public void sendTextReply(String, androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class ConversationItem implements androidx.car.app.model.Item {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.messaging.model.ConversationCallbackDelegate getConversationCallbackDelegate();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public String getId();
+    method public java.util.List<androidx.car.app.messaging.model.CarMessage!> getMessages();
+    method public androidx.core.app.Person getSelf();
+    method public androidx.car.app.model.CarText getTitle();
+    method public boolean isGroupConversation();
+  }
+
+  public static final class ConversationItem.Builder {
+    ctor public ConversationItem.Builder();
+    ctor public ConversationItem.Builder(androidx.car.app.messaging.model.ConversationItem);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.messaging.model.ConversationItem build();
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setConversationCallback(androidx.car.app.messaging.model.ConversationCallback);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setGroupConversation(boolean);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setId(String);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setMessages(java.util.List<androidx.car.app.messaging.model.CarMessage!>);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setSelf(androidx.core.app.Person);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setTitle(androidx.car.app.model.CarText);
+  }
+
+}
+
+package androidx.car.app.model {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Action {
+    method public androidx.car.app.model.CarColor? getBackgroundColor();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public int getFlags();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public int getType();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+    method public boolean isStandard();
+    method public static String typeToString(int);
+    field public static final androidx.car.app.model.Action APP_ICON;
+    field public static final androidx.car.app.model.Action BACK;
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.Action COMPOSE_MESSAGE;
+    field @androidx.car.app.annotations.RequiresCarApi(5) public static final int FLAG_DEFAULT = 4; // 0x4
+    field @androidx.car.app.annotations.RequiresCarApi(5) public static final int FLAG_IS_PERSISTENT = 2; // 0x2
+    field @androidx.car.app.annotations.RequiresCarApi(4) public static final int FLAG_PRIMARY = 1; // 0x1
+    field public static final androidx.car.app.model.Action PAN;
+    field public static final int TYPE_APP_ICON = 65538; // 0x10002
+    field public static final int TYPE_BACK = 65539; // 0x10003
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int TYPE_COMPOSE_MESSAGE = 65541; // 0x10005
+    field public static final int TYPE_CUSTOM = 1; // 0x1
+    field public static final int TYPE_PAN = 65540; // 0x10004
+  }
+
+  public static final class Action.Builder {
+    ctor public Action.Builder();
+    ctor @androidx.car.app.annotations.RequiresCarApi(2) public Action.Builder(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Action build();
+    method public androidx.car.app.model.Action.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Action.Builder setEnabled(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.Action.Builder setFlags(int);
+    method public androidx.car.app.model.Action.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Action.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+    method public androidx.car.app.model.Action.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.Action.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ActionStrip {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.Action? getFirstActionOfType(int);
+  }
+
+  public static final class ActionStrip.Builder {
+    ctor public ActionStrip.Builder();
+    method public androidx.car.app.model.ActionStrip.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.ActionStrip build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class Alert {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.AlertCallbackDelegate? getCallbackDelegate();
+    method public long getDurationMillis();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public int getId();
+    method public androidx.car.app.model.CarText? getSubtitle();
+    method public androidx.car.app.model.CarText getTitle();
+  }
+
+  public static final class Alert.Builder {
+    ctor public Alert.Builder(int, androidx.car.app.model.CarText, long);
+    method public androidx.car.app.model.Alert.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Alert build();
+    method public androidx.car.app.model.Alert.Builder setCallback(androidx.car.app.model.AlertCallback);
+    method public androidx.car.app.model.Alert.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Alert.Builder setSubtitle(androidx.car.app.model.CarText);
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallback {
+    method public void onCancel(int);
+    method public void onDismiss();
+    field public static final int REASON_NOT_SUPPORTED = 3; // 0x3
+    field public static final int REASON_TIMEOUT = 1; // 0x1
+    field public static final int REASON_USER_ACTION = 2; // 0x2
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallbackDelegate {
+    method public void sendCancel(int, androidx.car.app.OnDoneCallback);
+    method public void sendDismiss(androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class Badge {
+    method public androidx.car.app.model.CarColor? getBackgroundColor();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public boolean hasDot();
+  }
+
+  public static final class Badge.Builder {
+    ctor public Badge.Builder();
+    method public androidx.car.app.model.Badge build();
+    method public androidx.car.app.model.Badge.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.model.Badge.Builder setHasDot(boolean);
+    method public androidx.car.app.model.Badge.Builder setIcon(androidx.car.app.model.CarIcon);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarColor {
+    method public static androidx.car.app.model.CarColor createCustom(@ColorInt int, @ColorInt int);
+    method @ColorInt public int getColor();
+    method @ColorInt public int getColorDark();
+    method public int getType();
+    field public static final androidx.car.app.model.CarColor BLUE;
+    field public static final androidx.car.app.model.CarColor DEFAULT;
+    field public static final androidx.car.app.model.CarColor GREEN;
+    field public static final androidx.car.app.model.CarColor PRIMARY;
+    field public static final androidx.car.app.model.CarColor RED;
+    field public static final androidx.car.app.model.CarColor SECONDARY;
+    field public static final int TYPE_BLUE = 6; // 0x6
+    field public static final int TYPE_CUSTOM = 0; // 0x0
+    field public static final int TYPE_DEFAULT = 1; // 0x1
+    field public static final int TYPE_GREEN = 5; // 0x5
+    field public static final int TYPE_PRIMARY = 2; // 0x2
+    field public static final int TYPE_RED = 4; // 0x4
+    field public static final int TYPE_SECONDARY = 3; // 0x3
+    field public static final int TYPE_YELLOW = 7; // 0x7
+    field public static final androidx.car.app.model.CarColor YELLOW;
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarIcon {
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
+    method public androidx.car.app.model.CarColor? getTint();
+    method public int getType();
+    field public static final androidx.car.app.model.CarIcon ALERT;
+    field public static final androidx.car.app.model.CarIcon APP_ICON;
+    field public static final androidx.car.app.model.CarIcon BACK;
+    field @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.CarIcon COMPOSE_MESSAGE;
+    field public static final androidx.car.app.model.CarIcon ERROR;
+    field @androidx.car.app.annotations.RequiresCarApi(2) public static final androidx.car.app.model.CarIcon PAN;
+    field public static final int TYPE_ALERT = 4; // 0x4
+    field public static final int TYPE_APP_ICON = 5; // 0x5
+    field public static final int TYPE_BACK = 3; // 0x3
+    field public static final int TYPE_COMPOSE_MESSAGE = 8; // 0x8
+    field public static final int TYPE_CUSTOM = 1; // 0x1
+    field public static final int TYPE_ERROR = 6; // 0x6
+    field public static final int TYPE_PAN = 7; // 0x7
+  }
+
+  public static final class CarIcon.Builder {
+    ctor public CarIcon.Builder(androidx.car.app.model.CarIcon);
+    ctor public CarIcon.Builder(androidx.core.graphics.drawable.IconCompat);
+    method public androidx.car.app.model.CarIcon build();
+    method public androidx.car.app.model.CarIcon.Builder setTint(androidx.car.app.model.CarColor);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarIconSpan extends androidx.car.app.model.CarSpan {
+    method public static androidx.car.app.model.CarIconSpan create(androidx.car.app.model.CarIcon);
+    method public static androidx.car.app.model.CarIconSpan create(androidx.car.app.model.CarIcon, int);
+    method public int getAlignment();
+    method public androidx.car.app.model.CarIcon getIcon();
+    field public static final int ALIGN_BASELINE = 1; // 0x1
+    field public static final int ALIGN_BOTTOM = 0; // 0x0
+    field public static final int ALIGN_CENTER = 2; // 0x2
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarLocation {
+    method public static androidx.car.app.model.CarLocation create(android.location.Location);
+    method public static androidx.car.app.model.CarLocation create(double, double);
+    method public double getLatitude();
+    method public double getLongitude();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public class CarSpan extends android.text.style.CharacterStyle {
+    ctor public CarSpan();
+    method public void updateDrawState(android.text.TextPaint);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarText {
+    method public static androidx.car.app.model.CarText create(CharSequence);
+    method public java.util.List<java.lang.CharSequence!> getVariants();
+    method public boolean isEmpty();
+    method public static boolean isNullOrEmpty(androidx.car.app.model.CarText?);
+    method public CharSequence toCharSequence();
+  }
+
+  @SuppressCompatibility public static final class CarText.Builder {
+    ctor public CarText.Builder(CharSequence);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.CarText.Builder addVariant(CharSequence);
+    method public androidx.car.app.model.CarText build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(2) public final class ClickableSpan extends androidx.car.app.model.CarSpan {
+    method public static androidx.car.app.model.ClickableSpan create(androidx.car.app.model.OnClickListener);
+    method public androidx.car.app.model.OnClickDelegate getOnClickDelegate();
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public interface Content {
+    method public String getContentId();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DateTimeWithZone {
+    method @RequiresApi(26) public static androidx.car.app.model.DateTimeWithZone create(java.time.ZonedDateTime);
+    method public static androidx.car.app.model.DateTimeWithZone create(long, @IntRange(from=0xffff02e0, to=64800) int, String);
+    method public static androidx.car.app.model.DateTimeWithZone create(long, java.util.TimeZone);
+    method public long getTimeSinceEpochMillis();
+    method public int getZoneOffsetSeconds();
+    method public String? getZoneShortName();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Distance {
+    method public static androidx.car.app.model.Distance create(double, int);
+    method public double getDisplayDistance();
+    method public int getDisplayUnit();
+    field public static final int UNIT_FEET = 6; // 0x6
+    field public static final int UNIT_KILOMETERS = 2; // 0x2
+    field public static final int UNIT_KILOMETERS_P1 = 3; // 0x3
+    field public static final int UNIT_METERS = 1; // 0x1
+    field public static final int UNIT_MILES = 4; // 0x4
+    field public static final int UNIT_MILES_P1 = 5; // 0x5
+    field public static final int UNIT_YARDS = 7; // 0x7
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DistanceSpan extends androidx.car.app.model.CarSpan {
+    method public static androidx.car.app.model.DistanceSpan create(androidx.car.app.model.Distance);
+    method public androidx.car.app.model.Distance getDistance();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DurationSpan extends androidx.car.app.model.CarSpan {
+    method @RequiresApi(26) public static androidx.car.app.model.DurationSpan create(java.time.Duration);
+    method public static androidx.car.app.model.DurationSpan create(long);
+    method public long getDurationSeconds();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ForegroundCarColorSpan extends androidx.car.app.model.CarSpan {
+    method public static androidx.car.app.model.ForegroundCarColorSpan create(androidx.car.app.model.CarColor);
+    method public androidx.car.app.model.CarColor getColor();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class GridItem implements androidx.car.app.model.Item {
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.Badge? getBadge();
+    method public androidx.car.app.model.CarIcon? getImage();
+    method public int getImageType();
+    method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+    method public androidx.car.app.model.CarText? getText();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+    field public static final int IMAGE_TYPE_ICON = 1; // 0x1
+    field public static final int IMAGE_TYPE_LARGE = 2; // 0x2
+  }
+
+  public static final class GridItem.Builder {
+    ctor public GridItem.Builder();
+    method public androidx.car.app.model.GridItem build();
+    method public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, androidx.car.app.model.Badge);
+    method public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, int);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, int, androidx.car.app.model.Badge);
+    method public androidx.car.app.model.GridItem.Builder setLoading(boolean);
+    method public androidx.car.app.model.GridItem.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+    method public androidx.car.app.model.GridItem.Builder setText(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.GridItem.Builder setText(CharSequence);
+    method public androidx.car.app.model.GridItem.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.GridItem.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class GridTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemImageShape();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemSize();
+    method public androidx.car.app.model.ItemList? getSingleList();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_CIRCLE = 2; // 0x2
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_UNSET = 1; // 0x1
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_LARGE = 4; // 0x4
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_MEDIUM = 2; // 0x2
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_SMALL = 1; // 0x1
+  }
+
+  public static final class GridTemplate.Builder {
+    ctor public GridTemplate.Builder();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.GridTemplate build();
+    method public androidx.car.app.model.GridTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.GridTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemImageShape(@SuppressCompatibility int);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemSize(@SuppressCompatibility int);
+    method public androidx.car.app.model.GridTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.GridTemplate.Builder setSingleList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.model.GridTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class Header {
+    method public java.util.List<androidx.car.app.model.Action!> getEndHeaderActions();
+    method public androidx.car.app.model.Action? getStartHeaderAction();
+    method public androidx.car.app.model.CarText? getTitle();
+  }
+
+  public static final class Header.Builder {
+    ctor public Header.Builder();
+    method public androidx.car.app.model.Header.Builder addEndHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Header build();
+    method public androidx.car.app.model.Header.Builder setStartHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Header.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.Header.Builder setTitle(CharSequence);
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public interface InputCallback {
+    method public default void onInputSubmitted(String);
+    method public default void onInputTextChanged(String);
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public interface InputCallbackDelegate {
+    method public void sendInputSubmitted(String, androidx.car.app.OnDoneCallback);
+    method public void sendInputTextChanged(String, androidx.car.app.OnDoneCallback);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface Item {
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ItemList {
+    method public java.util.List<androidx.car.app.model.Item!> getItems();
+    method public androidx.car.app.model.CarText? getNoItemsMessage();
+    method public androidx.car.app.model.OnItemVisibilityChangedDelegate? getOnItemVisibilityChangedDelegate();
+    method public androidx.car.app.model.OnSelectedDelegate? getOnSelectedDelegate();
+    method public int getSelectedIndex();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ItemList.Builder toBuilder();
+  }
+
+  public static final class ItemList.Builder {
+    ctor public ItemList.Builder();
+    method public androidx.car.app.model.ItemList.Builder addItem(androidx.car.app.model.Item);
+    method public androidx.car.app.model.ItemList build();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ItemList.Builder clearItems();
+    method public androidx.car.app.model.ItemList.Builder setNoItemsMessage(CharSequence);
+    method public androidx.car.app.model.ItemList.Builder setOnItemsVisibilityChangedListener(androidx.car.app.model.ItemList.OnItemVisibilityChangedListener);
+    method public androidx.car.app.model.ItemList.Builder setOnSelectedListener(androidx.car.app.model.ItemList.OnSelectedListener);
+    method public androidx.car.app.model.ItemList.Builder setSelectedIndex(@IntRange(from=0) int);
+  }
+
+  public static interface ItemList.OnItemVisibilityChangedListener {
+    method public void onItemVisibilityChanged(int, int);
+  }
+
+  public static interface ItemList.OnSelectedListener {
+    method public void onSelected(int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ListTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public java.util.List<androidx.car.app.model.SectionedItemList!> getSectionedLists();
+    method public androidx.car.app.model.ItemList? getSingleList();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder toBuilder();
+  }
+
+  public static final class ListTemplate.Builder {
+    ctor public ListTemplate.Builder();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.ListTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.ListTemplate.Builder addSectionedList(androidx.car.app.model.SectionedItemList);
+    method public androidx.car.app.model.ListTemplate build();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder clearSectionedLists();
+    method public androidx.car.app.model.ListTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.ListTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.ListTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.ListTemplate.Builder setSingleList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.model.ListTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class LongMessageTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.CarText getMessage();
+    method public androidx.car.app.model.CarText? getTitle();
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public static final class LongMessageTemplate.Builder {
+    ctor public LongMessageTemplate.Builder(CharSequence);
+    method public androidx.car.app.model.LongMessageTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.LongMessageTemplate build();
+    method public androidx.car.app.model.LongMessageTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.LongMessageTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.LongMessageTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class MessageTemplate implements androidx.car.app.model.Template {
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.CarText? getDebugMessage();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public androidx.car.app.model.CarText getMessage();
+    method public androidx.car.app.model.CarText? getTitle();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public boolean isLoading();
+  }
+
+  public static final class MessageTemplate.Builder {
+    ctor public MessageTemplate.Builder(androidx.car.app.model.CarText);
+    ctor public MessageTemplate.Builder(CharSequence);
+    method public androidx.car.app.model.MessageTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.MessageTemplate build();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.MessageTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.MessageTemplate.Builder setDebugMessage(String);
+    method public androidx.car.app.model.MessageTemplate.Builder setDebugMessage(Throwable);
+    method public androidx.car.app.model.MessageTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.MessageTemplate.Builder setIcon(androidx.car.app.model.CarIcon);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.MessageTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.MessageTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Metadata {
+    method public androidx.car.app.model.Place? getPlace();
+    field public static final androidx.car.app.model.Metadata EMPTY_METADATA;
+  }
+
+  public static final class Metadata.Builder {
+    ctor public Metadata.Builder();
+    ctor public Metadata.Builder(androidx.car.app.model.Metadata);
+    method public androidx.car.app.model.Metadata build();
+    method public androidx.car.app.model.Metadata.Builder setPlace(androidx.car.app.model.Place);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnCheckedChangeDelegate {
+    method public void sendCheckedChange(boolean, androidx.car.app.OnDoneCallback);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnClickDelegate {
+    method public boolean isParkedOnly();
+    method public void sendClick(androidx.car.app.OnDoneCallback);
+  }
+
+  public interface OnClickListener {
+    method public void onClick();
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface OnContentRefreshDelegate {
+    method public void sendContentRefreshRequested(androidx.car.app.OnDoneCallback);
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(5) public interface OnContentRefreshListener {
+    method public void onContentRefreshRequested();
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnItemVisibilityChangedDelegate {
+    method public void sendItemVisibilityChanged(int, int, androidx.car.app.OnDoneCallback);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnSelectedDelegate {
+    method public void sendSelected(int, androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Pane {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.CarIcon? getImage();
+    method public java.util.List<androidx.car.app.model.Row!> getRows();
+    method public boolean isLoading();
+  }
+
+  public static final class Pane.Builder {
+    ctor public Pane.Builder();
+    method public androidx.car.app.model.Pane.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Pane.Builder addRow(androidx.car.app.model.Row);
+    method public androidx.car.app.model.Pane build();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.Pane.Builder setImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Pane.Builder setLoading(boolean);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PaneTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.Pane getPane();
+    method public androidx.car.app.model.CarText? getTitle();
+  }
+
+  public static final class PaneTemplate.Builder {
+    ctor public PaneTemplate.Builder(androidx.car.app.model.Pane);
+    method public androidx.car.app.model.PaneTemplate build();
+    method public androidx.car.app.model.PaneTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.PaneTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.PaneTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ParkedOnlyOnClickListener implements androidx.car.app.model.OnClickListener {
+    method public static androidx.car.app.model.ParkedOnlyOnClickListener create(androidx.car.app.model.OnClickListener);
+    method public void onClick();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Place {
+    method public androidx.car.app.model.CarLocation getLocation();
+    method public androidx.car.app.model.PlaceMarker? getMarker();
+  }
+
+  public static final class Place.Builder {
+    ctor public Place.Builder(androidx.car.app.model.CarLocation);
+    ctor public Place.Builder(androidx.car.app.model.Place);
+    method public androidx.car.app.model.Place build();
+    method public androidx.car.app.model.Place.Builder setMarker(androidx.car.app.model.PlaceMarker);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceListMapTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Place? getAnchor();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.OnContentRefreshDelegate? getOnContentRefreshDelegate();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isCurrentLocationEnabled();
+    method public boolean isLoading();
+  }
+
+  public static final class PlaceListMapTemplate.Builder {
+    ctor public PlaceListMapTemplate.Builder();
+    method public androidx.car.app.model.PlaceListMapTemplate build();
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setAnchor(androidx.car.app.model.Place);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setCurrentLocationEnabled(boolean);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setLoading(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.PlaceListMapTemplate.Builder setOnContentRefreshListener(androidx.car.app.model.OnContentRefreshListener);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceMarker {
+    method public androidx.car.app.model.CarColor? getColor();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public int getIconType();
+    method public androidx.car.app.model.CarText? getLabel();
+    field public static final int TYPE_ICON = 0; // 0x0
+    field public static final int TYPE_IMAGE = 1; // 0x1
+  }
+
+  public static final class PlaceMarker.Builder {
+    ctor public PlaceMarker.Builder();
+    method public androidx.car.app.model.PlaceMarker build();
+    method public androidx.car.app.model.PlaceMarker.Builder setColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.model.PlaceMarker.Builder setIcon(androidx.car.app.model.CarIcon, int);
+    method public androidx.car.app.model.PlaceMarker.Builder setLabel(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Row implements androidx.car.app.model.Item {
+    method @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.CarIcon? getImage();
+    method public androidx.car.app.model.Metadata? getMetadata();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public int getNumericDecoration();
+    method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+    method public int getRowImageType();
+    method public java.util.List<androidx.car.app.model.CarText!> getTexts();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public androidx.car.app.model.Toggle? getToggle();
+    method public boolean isBrowsable();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+    method public androidx.car.app.model.Row row();
+    method public CharSequence yourBoat();
+    field public static final int IMAGE_TYPE_ICON = 4; // 0x4
+    field public static final int IMAGE_TYPE_LARGE = 2; // 0x2
+    field public static final int IMAGE_TYPE_SMALL = 1; // 0x1
+    field public static final int NO_DECORATION = -1; // 0xffffffff
+  }
+
+  public static final class Row.Builder {
+    ctor public Row.Builder();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.Row.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Row.Builder addText(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.Row.Builder addText(CharSequence);
+    method public androidx.car.app.model.Row build();
+    method public androidx.car.app.model.Row.Builder setBrowsable(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Row.Builder setEnabled(boolean);
+    method public androidx.car.app.model.Row.Builder setImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Row.Builder setImage(androidx.car.app.model.CarIcon, int);
+    method public androidx.car.app.model.Row.Builder setMetadata(androidx.car.app.model.Metadata);
+    method @IntRange(from=0) @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.Row.Builder setNumericDecoration(int);
+    method public androidx.car.app.model.Row.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+    method public androidx.car.app.model.Row.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.Row.Builder setTitle(CharSequence);
+    method public androidx.car.app.model.Row.Builder setToggle(androidx.car.app.model.Toggle);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface SearchCallbackDelegate {
+    method public void sendSearchSubmitted(String, androidx.car.app.OnDoneCallback);
+    method public void sendSearchTextChanged(String, androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SearchTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public String? getInitialSearchText();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method public androidx.car.app.model.SearchCallbackDelegate getSearchCallbackDelegate();
+    method public String? getSearchHint();
+    method public boolean isLoading();
+    method public boolean isShowKeyboardByDefault();
+  }
+
+  public static final class SearchTemplate.Builder {
+    ctor public SearchTemplate.Builder(androidx.car.app.model.SearchTemplate.SearchCallback);
+    method public androidx.car.app.model.SearchTemplate build();
+    method public androidx.car.app.model.SearchTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.SearchTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.SearchTemplate.Builder setInitialSearchText(String);
+    method public androidx.car.app.model.SearchTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.model.SearchTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.SearchTemplate.Builder setSearchHint(String);
+    method public androidx.car.app.model.SearchTemplate.Builder setShowKeyboardByDefault(boolean);
+  }
+
+  public static interface SearchTemplate.SearchCallback {
+    method public default void onSearchSubmitted(String);
+    method public default void onSearchTextChanged(String);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SectionedItemList {
+    method public static androidx.car.app.model.SectionedItemList create(androidx.car.app.model.ItemList, CharSequence);
+    method public androidx.car.app.model.CarText getHeader();
+    method public androidx.car.app.model.ItemList getItemList();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public final class Tab implements androidx.car.app.model.Content {
+    method public String getContentId();
+    method public androidx.car.app.model.CarIcon getIcon();
+    method public androidx.car.app.model.CarText getTitle();
+  }
+
+  public static final class Tab.Builder {
+    ctor public Tab.Builder();
+    ctor public Tab.Builder(androidx.car.app.model.Tab);
+    method public androidx.car.app.model.Tab build();
+    method public androidx.car.app.model.Tab.Builder setContentId(String);
+    method public androidx.car.app.model.Tab.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Tab.Builder setTitle(CharSequence);
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public interface TabCallbackDelegate {
+    method public void sendTabSelected(String, androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class TabContents implements androidx.car.app.model.Content {
+    method public String getContentId();
+    method public androidx.car.app.model.Template getTemplate();
+    field public static final String CONTENT_ID = "TAB_CONTENTS_CONTENT_ID";
+  }
+
+  public static final class TabContents.Builder {
+    ctor public TabContents.Builder(androidx.car.app.model.Template);
+    method public androidx.car.app.model.TabContents build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class TabTemplate implements androidx.car.app.model.Template {
+    method public String getActiveTabContentId();
+    method public androidx.car.app.model.Action getHeaderAction();
+    method public androidx.car.app.model.TabCallbackDelegate getTabCallbackDelegate();
+    method public androidx.car.app.model.TabContents getTabContents();
+    method public java.util.List<androidx.car.app.model.Tab!> getTabs();
+    method public boolean isLoading();
+  }
+
+  public static final class TabTemplate.Builder {
+    ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate);
+    ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate.TabCallback);
+    method public androidx.car.app.model.TabTemplate.Builder addTab(androidx.car.app.model.Tab);
+    method public androidx.car.app.model.TabTemplate build();
+    method public androidx.car.app.model.TabTemplate.Builder setActiveTabContentId(String);
+    method public androidx.car.app.model.TabTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.TabTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.TabTemplate.Builder setTabContents(androidx.car.app.model.TabContents);
+  }
+
+  public static interface TabTemplate.TabCallback {
+    method public default void onTabSelected(String);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface Template {
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TemplateInfo {
+    ctor public TemplateInfo(Class<? extends androidx.car.app.model.Template>, String);
+    method public Class<? extends androidx.car.app.model.Template> getTemplateClass();
+    method public String getTemplateId();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TemplateWrapper {
+    method public static androidx.car.app.model.TemplateWrapper copyOf(androidx.car.app.model.TemplateWrapper);
+    method public int getCurrentTaskStep();
+    method public String getId();
+    method public androidx.car.app.model.Template getTemplate();
+    method public java.util.List<androidx.car.app.model.TemplateInfo!> getTemplateInfosForScreenStack();
+    method public boolean isRefresh();
+    method public void setCurrentTaskStep(int);
+    method public void setId(String);
+    method public void setRefresh(boolean);
+    method public void setTemplate(androidx.car.app.model.Template);
+    method public static androidx.car.app.model.TemplateWrapper wrap(androidx.car.app.model.Template);
+    method public static androidx.car.app.model.TemplateWrapper wrap(androidx.car.app.model.Template, String);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Toggle {
+    method public androidx.car.app.model.OnCheckedChangeDelegate getOnCheckedChangeDelegate();
+    method public boolean isChecked();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+  }
+
+  public static final class Toggle.Builder {
+    ctor public Toggle.Builder(androidx.car.app.model.Toggle.OnCheckedChangeListener);
+    method public androidx.car.app.model.Toggle build();
+    method public androidx.car.app.model.Toggle.Builder setChecked(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Toggle.Builder setEnabled(boolean);
+  }
+
+  public static interface Toggle.OnCheckedChangeListener {
+    method public void onCheckedChange(boolean);
+  }
+
+}
+
+package androidx.car.app.model.signin {
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class InputSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+    method public androidx.car.app.model.CarText? getDefaultValue();
+    method public androidx.car.app.model.CarText? getErrorMessage();
+    method public androidx.car.app.model.CarText? getHint();
+    method public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
+    method public int getInputType();
+    method public int getKeyboardType();
+    method public boolean isShowKeyboardByDefault();
+    field public static final int INPUT_TYPE_DEFAULT = 1; // 0x1
+    field public static final int INPUT_TYPE_PASSWORD = 2; // 0x2
+    field public static final int KEYBOARD_DEFAULT = 1; // 0x1
+    field public static final int KEYBOARD_EMAIL = 2; // 0x2
+    field public static final int KEYBOARD_NUMBER = 4; // 0x4
+    field public static final int KEYBOARD_PHONE = 3; // 0x3
+  }
+
+  public static final class InputSignInMethod.Builder {
+    ctor public InputSignInMethod.Builder(androidx.car.app.model.InputCallback);
+    method public androidx.car.app.model.signin.InputSignInMethod build();
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setDefaultValue(String);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setErrorMessage(CharSequence);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setHint(CharSequence);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setInputType(int);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setKeyboardType(int);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setShowKeyboardByDefault(boolean);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class PinSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+    ctor public PinSignInMethod(CharSequence);
+    method public androidx.car.app.model.CarText getPinCode();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class ProviderSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+    ctor public ProviderSignInMethod(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Action getAction();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(4) public final class QRCodeSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+    ctor public QRCodeSignInMethod(android.net.Uri);
+    method public android.net.Uri getUri();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class SignInTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.CarText? getAdditionalText();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.CarText? getInstructions();
+    method public androidx.car.app.model.signin.SignInTemplate.SignInMethod getSignInMethod();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public static final class SignInTemplate.Builder {
+    ctor public SignInTemplate.Builder(androidx.car.app.model.signin.SignInTemplate.SignInMethod);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.signin.SignInTemplate build();
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setAdditionalText(CharSequence);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setInstructions(CharSequence);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setTitle(CharSequence);
+  }
+
+  public static interface SignInTemplate.SignInMethod {
+  }
+
+}
+
+package androidx.car.app.navigation {
+
+  public class NavigationManager implements androidx.car.app.managers.Manager {
+    method @MainThread public void clearNavigationManagerCallback();
+    method @MainThread public void navigationEnded();
+    method @MainThread public void navigationStarted();
+    method @MainThread public void setNavigationManagerCallback(androidx.car.app.navigation.NavigationManagerCallback);
+    method @MainThread public void setNavigationManagerCallback(java.util.concurrent.Executor, androidx.car.app.navigation.NavigationManagerCallback);
+    method @MainThread public void updateTrip(androidx.car.app.navigation.model.Trip);
+  }
+
+  public interface NavigationManagerCallback {
+    method public default void onAutoDriveEnabled();
+    method public default void onStopNavigation();
+  }
+
+}
+
+package androidx.car.app.navigation.model {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Destination {
+    method public androidx.car.app.model.CarText? getAddress();
+    method public androidx.car.app.model.CarIcon? getImage();
+    method public androidx.car.app.model.CarText? getName();
+  }
+
+  public static final class Destination.Builder {
+    ctor public Destination.Builder();
+    method public androidx.car.app.navigation.model.Destination build();
+    method public androidx.car.app.navigation.model.Destination.Builder setAddress(CharSequence);
+    method public androidx.car.app.navigation.model.Destination.Builder setImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.Destination.Builder setName(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Lane {
+    method public java.util.List<androidx.car.app.navigation.model.LaneDirection!> getDirections();
+  }
+
+  public static final class Lane.Builder {
+    ctor public Lane.Builder();
+    method public androidx.car.app.navigation.model.Lane.Builder addDirection(androidx.car.app.navigation.model.LaneDirection);
+    method public androidx.car.app.navigation.model.Lane build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class LaneDirection {
+    method public static androidx.car.app.navigation.model.LaneDirection create(int, boolean);
+    method public int getShape();
+    method public boolean isRecommended();
+    field public static final int SHAPE_NORMAL_LEFT = 5; // 0x5
+    field public static final int SHAPE_NORMAL_RIGHT = 6; // 0x6
+    field public static final int SHAPE_SHARP_LEFT = 7; // 0x7
+    field public static final int SHAPE_SHARP_RIGHT = 8; // 0x8
+    field public static final int SHAPE_SLIGHT_LEFT = 3; // 0x3
+    field public static final int SHAPE_SLIGHT_RIGHT = 4; // 0x4
+    field public static final int SHAPE_STRAIGHT = 2; // 0x2
+    field public static final int SHAPE_UNKNOWN = 1; // 0x1
+    field public static final int SHAPE_U_TURN_LEFT = 9; // 0x9
+    field public static final int SHAPE_U_TURN_RIGHT = 10; // 0xa
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Maneuver {
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public int getRoundaboutExitAngle();
+    method public int getRoundaboutExitNumber();
+    method public int getType();
+    field public static final int TYPE_DEPART = 1; // 0x1
+    field public static final int TYPE_DESTINATION = 39; // 0x27
+    field public static final int TYPE_DESTINATION_LEFT = 41; // 0x29
+    field public static final int TYPE_DESTINATION_RIGHT = 42; // 0x2a
+    field public static final int TYPE_DESTINATION_STRAIGHT = 40; // 0x28
+    field public static final int TYPE_FERRY_BOAT = 37; // 0x25
+    field public static final int TYPE_FERRY_BOAT_LEFT = 47; // 0x2f
+    field public static final int TYPE_FERRY_BOAT_RIGHT = 48; // 0x30
+    field public static final int TYPE_FERRY_TRAIN = 38; // 0x26
+    field public static final int TYPE_FERRY_TRAIN_LEFT = 49; // 0x31
+    field public static final int TYPE_FERRY_TRAIN_RIGHT = 50; // 0x32
+    field public static final int TYPE_FORK_LEFT = 25; // 0x19
+    field public static final int TYPE_FORK_RIGHT = 26; // 0x1a
+    field public static final int TYPE_KEEP_LEFT = 3; // 0x3
+    field public static final int TYPE_KEEP_RIGHT = 4; // 0x4
+    field public static final int TYPE_MERGE_LEFT = 27; // 0x1b
+    field public static final int TYPE_MERGE_RIGHT = 28; // 0x1c
+    field public static final int TYPE_MERGE_SIDE_UNSPECIFIED = 29; // 0x1d
+    field public static final int TYPE_NAME_CHANGE = 2; // 0x2
+    field public static final int TYPE_OFF_RAMP_NORMAL_LEFT = 23; // 0x17
+    field public static final int TYPE_OFF_RAMP_NORMAL_RIGHT = 24; // 0x18
+    field public static final int TYPE_OFF_RAMP_SLIGHT_LEFT = 21; // 0x15
+    field public static final int TYPE_OFF_RAMP_SLIGHT_RIGHT = 22; // 0x16
+    field public static final int TYPE_ON_RAMP_NORMAL_LEFT = 15; // 0xf
+    field public static final int TYPE_ON_RAMP_NORMAL_RIGHT = 16; // 0x10
+    field public static final int TYPE_ON_RAMP_SHARP_LEFT = 17; // 0x11
+    field public static final int TYPE_ON_RAMP_SHARP_RIGHT = 18; // 0x12
+    field public static final int TYPE_ON_RAMP_SLIGHT_LEFT = 13; // 0xd
+    field public static final int TYPE_ON_RAMP_SLIGHT_RIGHT = 14; // 0xe
+    field public static final int TYPE_ON_RAMP_U_TURN_LEFT = 19; // 0x13
+    field public static final int TYPE_ON_RAMP_U_TURN_RIGHT = 20; // 0x14
+    field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW = 34; // 0x22
+    field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE = 35; // 0x23
+    field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW = 32; // 0x20
+    field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE = 33; // 0x21
+    field public static final int TYPE_ROUNDABOUT_ENTER_CCW = 45; // 0x2d
+    field public static final int TYPE_ROUNDABOUT_ENTER_CW = 43; // 0x2b
+    field public static final int TYPE_ROUNDABOUT_EXIT_CCW = 46; // 0x2e
+    field public static final int TYPE_ROUNDABOUT_EXIT_CW = 44; // 0x2c
+    field public static final int TYPE_STRAIGHT = 36; // 0x24
+    field public static final int TYPE_TURN_NORMAL_LEFT = 7; // 0x7
+    field public static final int TYPE_TURN_NORMAL_RIGHT = 8; // 0x8
+    field public static final int TYPE_TURN_SHARP_LEFT = 9; // 0x9
+    field public static final int TYPE_TURN_SHARP_RIGHT = 10; // 0xa
+    field public static final int TYPE_TURN_SLIGHT_LEFT = 5; // 0x5
+    field public static final int TYPE_TURN_SLIGHT_RIGHT = 6; // 0x6
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_U_TURN_LEFT = 11; // 0xb
+    field public static final int TYPE_U_TURN_RIGHT = 12; // 0xc
+  }
+
+  public static final class Maneuver.Builder {
+    ctor public Maneuver.Builder(int);
+    method public androidx.car.app.navigation.model.Maneuver build();
+    method public androidx.car.app.navigation.model.Maneuver.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.Maneuver.Builder setRoundaboutExitAngle(@IntRange(from=1, to=360) int);
+    method public androidx.car.app.navigation.model.Maneuver.Builder setRoundaboutExitNumber(@IntRange(from=1) int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class MapController {
+    method public androidx.car.app.model.ActionStrip? getMapActionStrip();
+    method public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+  }
+
+  public static final class MapController.Builder {
+    ctor public MapController.Builder();
+    method public androidx.car.app.navigation.model.MapController build();
+    method public androidx.car.app.navigation.model.MapController.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.MapController.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class MapTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Header? getHeader();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method public androidx.car.app.navigation.model.MapController? getMapController();
+    method public androidx.car.app.model.Pane? getPane();
+  }
+
+  public static final class MapTemplate.Builder {
+    ctor public MapTemplate.Builder();
+    method public androidx.car.app.navigation.model.MapTemplate build();
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setHeader(androidx.car.app.model.Header);
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setMapController(androidx.car.app.navigation.model.MapController);
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setPane(androidx.car.app.model.Pane);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public final class MapWithContentTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Template? getContentTemplate();
+    method public androidx.car.app.navigation.model.MapController? getMapController();
+    method public boolean isLoading();
+  }
+
+  public static final class MapWithContentTemplate.Builder {
+    ctor public MapWithContentTemplate.Builder();
+    method public androidx.car.app.navigation.model.MapWithContentTemplate build();
+    method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setContentTemplate(androidx.car.app.model.Template);
+    method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setMapController(androidx.car.app.navigation.model.MapController);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class MessageInfo implements androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo {
+    method public androidx.car.app.model.CarIcon? getImage();
+    method public androidx.car.app.model.CarText? getText();
+    method public androidx.car.app.model.CarText? getTitle();
+  }
+
+  public static final class MessageInfo.Builder {
+    ctor public MessageInfo.Builder(androidx.car.app.model.CarText);
+    ctor public MessageInfo.Builder(CharSequence);
+    method public androidx.car.app.navigation.model.MessageInfo build();
+    method public androidx.car.app.navigation.model.MessageInfo.Builder setImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.MessageInfo.Builder setText(androidx.car.app.model.CarText);
+    method public androidx.car.app.navigation.model.MessageInfo.Builder setText(CharSequence);
+    method public androidx.car.app.navigation.model.MessageInfo.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class NavigationTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.CarColor? getBackgroundColor();
+    method public androidx.car.app.navigation.model.TravelEstimate? getDestinationTravelEstimate();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+    method public androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo? getNavigationInfo();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+    method @Deprecated @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.Toggle? getPanModeToggle();
+  }
+
+  public static final class NavigationTemplate.Builder {
+    ctor public NavigationTemplate.Builder();
+    method public androidx.car.app.navigation.model.NavigationTemplate build();
+    method public androidx.car.app.navigation.model.NavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.NavigationTemplate.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.navigation.model.NavigationTemplate.Builder setDestinationTravelEstimate(androidx.car.app.navigation.model.TravelEstimate);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.NavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.NavigationTemplate.Builder setNavigationInfo(androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.NavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+  }
+
+  public static interface NavigationTemplate.NavigationInfo {
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(2) public interface PanModeDelegate {
+    method public void sendPanModeChanged(boolean, androidx.car.app.OnDoneCallback);
+  }
+
+  public interface PanModeListener {
+    method public void onPanModeChanged(boolean);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceListNavigationTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Header? getHeader();
+    method @Deprecated public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+    method public androidx.car.app.model.OnContentRefreshDelegate? getOnContentRefreshDelegate();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+    method @Deprecated public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+  }
+
+  public static final class PlaceListNavigationTemplate.Builder {
+    ctor public PlaceListNavigationTemplate.Builder();
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate build();
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setHeader(androidx.car.app.model.Header);
+    method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setLoading(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setOnContentRefreshListener(androidx.car.app.model.OnContentRefreshListener);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+    method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setTitle(androidx.car.app.model.CarText);
+    method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class RoutePreviewNavigationTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Header? getHeader();
+    method @Deprecated public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+    method public androidx.car.app.model.Action? getNavigateAction();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+    method @Deprecated public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+  }
+
+  public static final class RoutePreviewNavigationTemplate.Builder {
+    ctor public RoutePreviewNavigationTemplate.Builder();
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate build();
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setHeader(androidx.car.app.model.Header);
+    method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setLoading(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setNavigateAction(androidx.car.app.model.Action);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+    method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setTitle(androidx.car.app.model.CarText);
+    method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class RoutingInfo implements androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo {
+    method public androidx.car.app.model.Distance? getCurrentDistance();
+    method public androidx.car.app.navigation.model.Step? getCurrentStep();
+    method public androidx.car.app.model.CarIcon? getJunctionImage();
+    method public androidx.car.app.navigation.model.Step? getNextStep();
+    method public boolean isLoading();
+  }
+
+  public static final class RoutingInfo.Builder {
+    ctor public RoutingInfo.Builder();
+    method public androidx.car.app.navigation.model.RoutingInfo build();
+    method public androidx.car.app.navigation.model.RoutingInfo.Builder setCurrentStep(androidx.car.app.navigation.model.Step, androidx.car.app.model.Distance);
+    method public androidx.car.app.navigation.model.RoutingInfo.Builder setJunctionImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.RoutingInfo.Builder setLoading(boolean);
+    method public androidx.car.app.navigation.model.RoutingInfo.Builder setNextStep(androidx.car.app.navigation.model.Step);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Step {
+    method public androidx.car.app.model.CarText? getCue();
+    method public java.util.List<androidx.car.app.navigation.model.Lane!> getLanes();
+    method public androidx.car.app.model.CarIcon? getLanesImage();
+    method public androidx.car.app.navigation.model.Maneuver? getManeuver();
+    method public androidx.car.app.model.CarText? getRoad();
+  }
+
+  public static final class Step.Builder {
+    ctor public Step.Builder();
+    ctor public Step.Builder(androidx.car.app.model.CarText);
+    ctor public Step.Builder(CharSequence);
+    method public androidx.car.app.navigation.model.Step.Builder addLane(androidx.car.app.navigation.model.Lane);
+    method public androidx.car.app.navigation.model.Step build();
+    method public androidx.car.app.navigation.model.Step.Builder setCue(CharSequence);
+    method public androidx.car.app.navigation.model.Step.Builder setLanesImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.Step.Builder setManeuver(androidx.car.app.navigation.model.Maneuver);
+    method public androidx.car.app.navigation.model.Step.Builder setRoad(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TravelEstimate {
+    method public androidx.car.app.model.DateTimeWithZone? getArrivalTimeAtDestination();
+    method public androidx.car.app.model.Distance? getRemainingDistance();
+    method public androidx.car.app.model.CarColor? getRemainingDistanceColor();
+    method public androidx.car.app.model.CarColor? getRemainingTimeColor();
+    method public long getRemainingTimeSeconds();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.CarIcon? getTripIcon();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.CarText? getTripText();
+    field public static final long REMAINING_TIME_UNKNOWN = -1L; // 0xffffffffffffffffL
+  }
+
+  public static final class TravelEstimate.Builder {
+    ctor public TravelEstimate.Builder(androidx.car.app.model.Distance, androidx.car.app.model.DateTimeWithZone);
+    ctor @RequiresApi(26) public TravelEstimate.Builder(androidx.car.app.model.Distance, java.time.ZonedDateTime);
+    method public androidx.car.app.navigation.model.TravelEstimate build();
+    method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingDistanceColor(androidx.car.app.model.CarColor);
+    method @RequiresApi(26) public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTime(java.time.Duration);
+    method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTimeColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTimeSeconds(@IntRange(from=0xffffffff) long);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.TravelEstimate.Builder setTripIcon(androidx.car.app.model.CarIcon);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.TravelEstimate.Builder setTripText(androidx.car.app.model.CarText);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Trip {
+    method public androidx.car.app.model.CarText? getCurrentRoad();
+    method public java.util.List<androidx.car.app.navigation.model.TravelEstimate!> getDestinationTravelEstimates();
+    method public java.util.List<androidx.car.app.navigation.model.Destination!> getDestinations();
+    method public java.util.List<androidx.car.app.navigation.model.TravelEstimate!> getStepTravelEstimates();
+    method public java.util.List<androidx.car.app.navigation.model.Step!> getSteps();
+    method public boolean isLoading();
+  }
+
+  public static final class Trip.Builder {
+    ctor public Trip.Builder();
+    method public androidx.car.app.navigation.model.Trip.Builder addDestination(androidx.car.app.navigation.model.Destination, androidx.car.app.navigation.model.TravelEstimate);
+    method public androidx.car.app.navigation.model.Trip.Builder addStep(androidx.car.app.navigation.model.Step, androidx.car.app.navigation.model.TravelEstimate);
+    method public androidx.car.app.navigation.model.Trip build();
+    method public androidx.car.app.navigation.model.Trip.Builder setCurrentRoad(CharSequence);
+    method public androidx.car.app.navigation.model.Trip.Builder setLoading(boolean);
+  }
+
+}
+
+package androidx.car.app.notification {
+
+  public final class CarAppExtender implements androidx.core.app.NotificationCompat.Extender {
+    ctor public CarAppExtender(android.app.Notification);
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+    method public java.util.List<android.app.Notification.Action!> getActions();
+    method public String? getChannelId();
+    method public androidx.car.app.model.CarColor? getColor();
+    method public android.app.PendingIntent? getContentIntent();
+    method public CharSequence? getContentText();
+    method public CharSequence? getContentTitle();
+    method public android.app.PendingIntent? getDeleteIntent();
+    method public int getImportance();
+    method public android.graphics.Bitmap? getLargeIcon();
+    method @DrawableRes public int getSmallIcon();
+    method public static boolean isExtended(android.app.Notification);
+  }
+
+  public static final class CarAppExtender.Builder {
+    ctor public CarAppExtender.Builder();
+    method public androidx.car.app.notification.CarAppExtender.Builder addAction(@DrawableRes int, CharSequence, android.app.PendingIntent);
+    method public androidx.car.app.notification.CarAppExtender build();
+    method public androidx.car.app.notification.CarAppExtender.Builder setChannelId(String);
+    method public androidx.car.app.notification.CarAppExtender.Builder setColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.notification.CarAppExtender.Builder setContentIntent(android.app.PendingIntent);
+    method public androidx.car.app.notification.CarAppExtender.Builder setContentText(CharSequence);
+    method public androidx.car.app.notification.CarAppExtender.Builder setContentTitle(CharSequence);
+    method public androidx.car.app.notification.CarAppExtender.Builder setDeleteIntent(android.app.PendingIntent);
+    method public androidx.car.app.notification.CarAppExtender.Builder setImportance(int);
+    method public androidx.car.app.notification.CarAppExtender.Builder setLargeIcon(android.graphics.Bitmap);
+    method public androidx.car.app.notification.CarAppExtender.Builder setSmallIcon(int);
+  }
+
+  public final class CarNotificationManager {
+    method public boolean areNotificationsEnabled();
+    method public void cancel(int);
+    method public void cancel(String?, int);
+    method public void cancelAll();
+    method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+    method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+    method public void createNotificationChannelGroups(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+    method public void createNotificationChannels(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+    method public void deleteNotificationChannel(String);
+    method public void deleteNotificationChannelGroup(String);
+    method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+    method public static androidx.car.app.notification.CarNotificationManager from(android.content.Context);
+    method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+    method public int getImportance();
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannel(String);
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannel(String, String);
+    method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroup(String);
+    method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroups();
+    method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannels();
+    method public void notify(int, androidx.core.app.NotificationCompat.Builder);
+    method public void notify(String?, int, androidx.core.app.NotificationCompat.Builder);
+  }
+
+  public final class CarPendingIntent {
+    method public static android.app.PendingIntent getCarApp(android.content.Context, int, android.content.Intent, int);
+  }
+
+}
+
+package androidx.car.app.serialization {
+
+  public final class Bundleable implements android.os.Parcelable {
+    method public static androidx.car.app.serialization.Bundleable create(Object) throws androidx.car.app.serialization.BundlerException;
+    method public int describeContents();
+    method public Object get() throws androidx.car.app.serialization.BundlerException;
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.car.app.serialization.Bundleable!> CREATOR;
+  }
+
+  public class BundlerException extends java.lang.Exception {
+    ctor public BundlerException(String?);
+    ctor public BundlerException(String?, Throwable);
+  }
+
+}
+
+package androidx.car.app.suggestion {
+
+  @androidx.car.app.annotations.RequiresCarApi(5) public class SuggestionManager implements androidx.car.app.managers.Manager {
+    method @MainThread public void updateSuggestions(java.util.List<androidx.car.app.suggestion.model.Suggestion!>);
+  }
+
+}
+
+package androidx.car.app.suggestion.model {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Suggestion {
+    method public android.app.PendingIntent? getAction();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public String getIdentifier();
+    method public androidx.car.app.model.CarText? getSubtitle();
+    method public androidx.car.app.model.CarText getTitle();
+  }
+
+  public static final class Suggestion.Builder {
+    ctor public Suggestion.Builder();
+    method public androidx.car.app.suggestion.model.Suggestion build();
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setAction(android.app.PendingIntent);
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setIdentifier(String);
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setSubtitle(CharSequence);
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setTitle(CharSequence);
+  }
+
+}
+
+package androidx.car.app.validation {
+
+  public final class HostValidator {
+    method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getAllowedHosts();
+    method public boolean isValidHost(androidx.car.app.HostInfo);
+    field public static final androidx.car.app.validation.HostValidator ALLOW_ALL_HOSTS_VALIDATOR;
+    field public static final String TEMPLATE_RENDERER_PERMISSION = "android.car.permission.TEMPLATE_RENDERER";
+  }
+
+  public static final class HostValidator.Builder {
+    ctor public HostValidator.Builder(android.content.Context);
+    method public androidx.car.app.validation.HostValidator.Builder addAllowedHost(String, String);
+    method public androidx.car.app.validation.HostValidator.Builder addAllowedHosts(@ArrayRes int);
+    method public androidx.car.app.validation.HostValidator build();
+  }
+
+}
+
+package androidx.car.app.versioning {
+
+  public final class CarAppApiLevels {
+    method public static int getLatest();
+    method public static int getOldest();
+    field public static final int LEVEL_1 = 1; // 0x1
+    field public static final int LEVEL_2 = 2; // 0x2
+    field public static final int LEVEL_3 = 3; // 0x3
+    field public static final int LEVEL_4 = 4; // 0x4
+    field public static final int LEVEL_5 = 5; // 0x5
+    field public static final int LEVEL_6 = 6; // 0x6
+    field public static final int LEVEL_7 = 7; // 0x7
+  }
+
+}
+
diff --git a/car/app/app/api/res-1.4.0-beta01.txt b/car/app/app/api/res-1.4.0-beta01.txt
new file mode 100644
index 0000000..686fc80
--- /dev/null
+++ b/car/app/app/api/res-1.4.0-beta01.txt
@@ -0,0 +1,5 @@
+attr carColorPrimary
+attr carColorPrimaryDark
+attr carColorSecondary
+attr carColorSecondaryDark
+attr carPermissionActivityLayout
diff --git a/car/app/app/api/restricted_1.4.0-beta01.txt b/car/app/app/api/restricted_1.4.0-beta01.txt
new file mode 100644
index 0000000..73c12de
--- /dev/null
+++ b/car/app/app/api/restricted_1.4.0-beta01.txt
@@ -0,0 +1,2210 @@
+// Signature format: 4.0
+package androidx.car.app {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class AppInfo {
+    ctor @VisibleForTesting public AppInfo(int, int, String);
+    method public int getLatestCarAppApiLevel();
+    method public String getLibraryDisplayVersion();
+    method public int getMinCarAppApiLevel();
+    field public static final String MIN_API_LEVEL_METADATA_KEY = "androidx.car.app.minCarApiLevel";
+  }
+
+  public class AppManager implements androidx.car.app.managers.Manager {
+    method @androidx.car.app.annotations.RequiresCarApi(5) public void dismissAlert(int);
+    method public void invalidate();
+    method public void setSurfaceCallback(androidx.car.app.SurfaceCallback?);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public void showAlert(androidx.car.app.model.Alert);
+    method public void showToast(CharSequence, int);
+  }
+
+  public final class CarAppPermission {
+    method public static void checkHasLibraryPermission(android.content.Context, String);
+    method public static void checkHasPermission(android.content.Context, String);
+    field public static final String ACCESS_SURFACE = "androidx.car.app.ACCESS_SURFACE";
+    field public static final String MAP_TEMPLATES = "androidx.car.app.MAP_TEMPLATES";
+    field public static final String NAVIGATION_TEMPLATES = "androidx.car.app.NAVIGATION_TEMPLATES";
+  }
+
+  public abstract class CarAppService extends android.app.Service {
+    ctor public CarAppService();
+    method public abstract androidx.car.app.validation.HostValidator createHostValidator();
+    method @CallSuper public final void dump(java.io.FileDescriptor, java.io.PrintWriter, String![]?);
+    method @Deprecated public final androidx.car.app.Session? getCurrentSession();
+    method public final androidx.car.app.HostInfo? getHostInfo();
+    method public final androidx.car.app.Session? getSession(androidx.car.app.SessionInfo);
+    method @CallSuper public final android.os.IBinder onBind(android.content.Intent);
+    method public androidx.car.app.Session onCreateSession();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.Session onCreateSession(androidx.car.app.SessionInfo);
+    method public final boolean onUnbind(android.content.Intent);
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_CALLING_APP = "androidx.car.app.category.CALLING";
+    field @Deprecated public static final String CATEGORY_CHARGING_APP = "androidx.car.app.category.CHARGING";
+    field @androidx.car.app.annotations.RequiresCarApi(6) public static final String CATEGORY_FEATURE_CLUSTER = "androidx.car.app.category.FEATURE_CLUSTER";
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_IOT_APP = "androidx.car.app.category.IOT";
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_MESSAGING_APP = "androidx.car.app.category.MESSAGING";
+    field public static final String CATEGORY_NAVIGATION_APP = "androidx.car.app.category.NAVIGATION";
+    field @Deprecated public static final String CATEGORY_PARKING_APP = "androidx.car.app.category.PARKING";
+    field public static final String CATEGORY_POI_APP = "androidx.car.app.category.POI";
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_SETTINGS_APP = "androidx.car.app.category.SETTINGS";
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_WEATHER_APP = "androidx.car.app.category.WEATHER";
+    field public static final String SERVICE_INTERFACE = "androidx.car.app.CarAppService";
+  }
+
+  public class CarContext extends android.content.ContextWrapper {
+    method public void finishCarApp();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public android.content.ComponentName? getCallingComponent();
+    method public int getCarAppApiLevel();
+    method public <T> T getCarService(Class<T!>);
+    method public Object getCarService(String);
+    method public String getCarServiceName(Class<?>);
+    method public androidx.car.app.HostInfo? getHostInfo();
+    method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+    method public boolean isDarkMode();
+    method public void requestPermissions(java.util.List<java.lang.String!>, androidx.car.app.OnRequestPermissionsListener);
+    method public void requestPermissions(java.util.List<java.lang.String!>, java.util.concurrent.Executor, androidx.car.app.OnRequestPermissionsListener);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public void setCarAppResult(int, android.content.Intent?);
+    method public void startCarApp(android.content.Intent);
+    method @Deprecated public static void startCarApp(android.content.Intent, android.content.Intent);
+    field public static final String ACTION_NAVIGATE = "androidx.car.app.action.NAVIGATE";
+    field public static final String APP_SERVICE = "app";
+    field public static final String CAR_SERVICE = "car";
+    field @androidx.car.app.annotations.RequiresCarApi(2) public static final String CONSTRAINT_SERVICE = "constraints";
+    field public static final String EXTRA_START_CAR_APP_BINDER_KEY = "androidx.car.app.extra.START_CAR_APP_BINDER_KEY";
+    field @androidx.car.app.annotations.RequiresCarApi(3) public static final String HARDWARE_SERVICE = "hardware";
+    field public static final String NAVIGATION_SERVICE = "navigation";
+    field public static final String SCREEN_SERVICE = "screen";
+    field public static final String SUGGESTION_SERVICE = "suggestion";
+  }
+
+  public final class CarToast {
+    method public static androidx.car.app.CarToast makeText(androidx.car.app.CarContext, @StringRes int, int);
+    method public static androidx.car.app.CarToast makeText(androidx.car.app.CarContext, CharSequence, int);
+    method public void setDuration(int);
+    method public void setText(@StringRes int);
+    method public void setText(CharSequence);
+    method public void show();
+    field public static final int LENGTH_LONG = 1; // 0x1
+    field public static final int LENGTH_SHORT = 0; // 0x0
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class FailureResponse {
+    ctor public FailureResponse(Throwable);
+    method public int getErrorType();
+    method public String getStackTrace();
+    field public static final int BUNDLER_EXCEPTION = 1; // 0x1
+    field public static final int ILLEGAL_STATE_EXCEPTION = 2; // 0x2
+    field public static final int INVALID_PARAMETER_EXCEPTION = 3; // 0x3
+    field public static final int REMOTE_EXCEPTION = 6; // 0x6
+    field public static final int RUNTIME_EXCEPTION = 5; // 0x5
+    field public static final int SECURITY_EXCEPTION = 4; // 0x4
+    field public static final int UNKNOWN_ERROR = 0; // 0x0
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class HandshakeInfo {
+    ctor public HandshakeInfo(String, int);
+    method public int getHostCarAppApiLevel();
+    method public String getHostPackageName();
+  }
+
+  public final class HostException extends java.lang.RuntimeException {
+    ctor public HostException(String);
+    ctor public HostException(String, Throwable);
+    ctor public HostException(Throwable);
+  }
+
+  public final class HostInfo {
+    ctor public HostInfo(String, int);
+    method public String getPackageName();
+    method public int getUid();
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnDoneCallback {
+    method public default void onFailure(androidx.car.app.serialization.Bundleable);
+    method public default void onSuccess(androidx.car.app.serialization.Bundleable?);
+  }
+
+  public interface OnRequestPermissionsListener {
+    method public void onRequestPermissionsResult(java.util.List<java.lang.String!>, java.util.List<java.lang.String!>);
+  }
+
+  public interface OnScreenResultListener {
+    method public void onScreenResult(Object?);
+  }
+
+  public abstract class Screen implements androidx.lifecycle.LifecycleOwner {
+    ctor protected Screen(androidx.car.app.CarContext);
+    method public final void finish();
+    method public final androidx.car.app.CarContext getCarContext();
+    method public final androidx.lifecycle.Lifecycle getLifecycle();
+    method public String? getMarker();
+    method public final androidx.car.app.ScreenManager getScreenManager();
+    method public final void invalidate();
+    method public abstract androidx.car.app.model.Template onGetTemplate();
+    method public void setMarker(String?);
+    method public void setResult(Object?);
+  }
+
+  @MainThread public class ScreenManager implements androidx.car.app.managers.Manager {
+    method public java.util.Collection<androidx.car.app.Screen!> getScreenStack();
+    method public int getStackSize();
+    method public androidx.car.app.Screen getTop();
+    method public void pop();
+    method public void popTo(String);
+    method public void popToRoot();
+    method public void push(androidx.car.app.Screen);
+    method public void pushForResult(androidx.car.app.Screen, androidx.car.app.OnScreenResultListener);
+    method public void remove(androidx.car.app.Screen);
+  }
+
+  public abstract class Session implements androidx.lifecycle.LifecycleOwner {
+    ctor public Session();
+    method public final androidx.car.app.CarContext getCarContext();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method public void onCarConfigurationChanged(android.content.res.Configuration);
+    method public abstract androidx.car.app.Screen onCreateScreen(android.content.Intent);
+    method public void onNewIntent(android.content.Intent);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class SessionInfo {
+    ctor public SessionInfo(int, String);
+    method public int getDisplayType();
+    method public String getSessionId();
+    method public java.util.Set<java.lang.Class<? extends androidx.car.app.model.Template>!>? getSupportedTemplates(int);
+    field public static final androidx.car.app.SessionInfo DEFAULT_SESSION_INFO;
+    field public static final int DISPLAY_TYPE_CLUSTER = 1; // 0x1
+    field public static final int DISPLAY_TYPE_MAIN = 0; // 0x0
+  }
+
+  public class SessionInfoIntentEncoder {
+    method public static boolean containsSessionInfo(android.content.Intent);
+    method public static androidx.car.app.SessionInfo decode(android.content.Intent);
+    method public static void encode(androidx.car.app.SessionInfo, android.content.Intent);
+  }
+
+  public interface SurfaceCallback {
+    method @androidx.car.app.annotations.RequiresCarApi(5) public default void onClick(float, float);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public default void onFling(float, float);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public default void onScale(float, float, float);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public default void onScroll(float, float);
+    method public default void onStableAreaChanged(android.graphics.Rect);
+    method public default void onSurfaceAvailable(androidx.car.app.SurfaceContainer);
+    method public default void onSurfaceDestroyed(androidx.car.app.SurfaceContainer);
+    method public default void onVisibleAreaChanged(android.graphics.Rect);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SurfaceContainer {
+    ctor public SurfaceContainer(android.view.Surface?, int, int, int);
+    method public int getDpi();
+    method public int getHeight();
+    method public android.view.Surface? getSurface();
+    method public int getWidth();
+  }
+
+}
+
+package androidx.car.app.annotations {
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.PARAMETER}) public @interface CarProtocol {
+  }
+
+  @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface ExperimentalCarApi {
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface RequiresCarApi {
+    method public abstract int value();
+  }
+
+}
+
+package androidx.car.app.connection {
+
+  public final class CarConnection {
+    ctor @MainThread public CarConnection(android.content.Context);
+    method public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
+    field public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
+    field public static final String CAR_CONNECTION_STATE = "CarConnectionState";
+    field public static final int CONNECTION_TYPE_NATIVE = 1; // 0x1
+    field public static final int CONNECTION_TYPE_NOT_CONNECTED = 0; // 0x0
+    field public static final int CONNECTION_TYPE_PROJECTION = 2; // 0x2
+  }
+
+}
+
+package androidx.car.app.constraints {
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public class ConstraintManager implements androidx.car.app.managers.Manager {
+    method public int getContentLimit(int);
+    method @androidx.car.app.annotations.RequiresCarApi(6) public boolean isAppDrivenRefreshEnabled();
+    field public static final int CONTENT_LIMIT_TYPE_GRID = 1; // 0x1
+    field public static final int CONTENT_LIMIT_TYPE_LIST = 0; // 0x0
+    field public static final int CONTENT_LIMIT_TYPE_PANE = 4; // 0x4
+    field public static final int CONTENT_LIMIT_TYPE_PLACE_LIST = 2; // 0x2
+    field public static final int CONTENT_LIMIT_TYPE_ROUTE_LIST = 3; // 0x3
+  }
+
+}
+
+package androidx.car.app.hardware {
+
+  @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarHardwareManager extends androidx.car.app.managers.Manager {
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public default androidx.car.app.hardware.climate.CarClimate getCarClimate();
+    method public default androidx.car.app.hardware.info.CarInfo getCarInfo();
+    method public default androidx.car.app.hardware.info.CarSensors getCarSensors();
+  }
+
+}
+
+package androidx.car.app.hardware.climate {
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CabinTemperatureProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Float!,java.lang.Float!>!> getCarZoneSetsToCabinCelsiusTemperatureRanges();
+    method public float getCelsiusSupportedIncrement();
+    method public float getFahrenheitSupportedIncrement();
+    method public android.util.Pair<java.lang.Float!,java.lang.Float!> getSupportedMinMaxCelsiusRange();
+    method public android.util.Pair<java.lang.Float!,java.lang.Float!> getSupportedMinMaxFahrenheitRange();
+    method public boolean hasCarZoneSetsToCabinCelsiusTemperatureRanges();
+    method public boolean hasCelsiusSupportedIncrement();
+    method public boolean hasFahrenheitSupportedIncrement();
+    method public boolean hasSupportedMinMaxCelsiusRange();
+    method public boolean hasSupportedMinMaxFahrenheitRange();
+  }
+
+  public static final class CabinTemperatureProfile.Builder {
+    ctor public CabinTemperatureProfile.Builder();
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile build();
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setCarZoneSetsToCabinCelsiusTemperatureRanges(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Float!,java.lang.Float!>!>);
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setCelsiusSupportedIncrement(float);
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setFahrenheitSupportedIncrement(float);
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setSupportedMinMaxCelsiusRange(android.util.Pair<java.lang.Float!,java.lang.Float!>);
+    method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setSupportedMinMaxFahrenheitRange(android.util.Pair<java.lang.Float!,java.lang.Float!>);
+  }
+
+  @SuppressCompatibility @MainThread @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimate {
+    method public void fetchClimateProfile(java.util.concurrent.Executor, androidx.car.app.hardware.climate.ClimateProfileRequest, androidx.car.app.hardware.climate.CarClimateProfileCallback);
+    method public void registerClimateStateCallback(java.util.concurrent.Executor, androidx.car.app.hardware.climate.RegisterClimateStateRequest, androidx.car.app.hardware.climate.CarClimateStateCallback);
+    method public <E> void setClimateState(java.util.concurrent.Executor, androidx.car.app.hardware.climate.ClimateStateRequest<E!>, androidx.car.app.hardware.common.CarSetOperationStatusCallback);
+    method public void unregisterClimateStateCallback(androidx.car.app.hardware.climate.CarClimateStateCallback);
+  }
+
+  @SuppressCompatibility @MainThread @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class CarClimateFeature {
+    method public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+    method public int getFeature();
+  }
+
+  public static final class CarClimateFeature.Builder {
+    ctor public CarClimateFeature.Builder(int);
+    method public androidx.car.app.hardware.climate.CarClimateFeature.Builder addCarZones(androidx.car.app.hardware.common.CarZone!...);
+    method public androidx.car.app.hardware.climate.CarClimateFeature build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimateProfileCallback {
+    method public default void onCabinTemperatureProfileAvailable(androidx.car.app.hardware.climate.CabinTemperatureProfile);
+    method public default void onCarZoneMappingInfoProfileAvailable(androidx.car.app.hardware.climate.CarZoneMappingInfoProfile);
+    method public default void onDefrosterProfileAvailable(androidx.car.app.hardware.climate.DefrosterProfile);
+    method public default void onElectricDefrosterProfileAvailable(androidx.car.app.hardware.climate.ElectricDefrosterProfile);
+    method public default void onFanDirectionProfileAvailable(androidx.car.app.hardware.climate.FanDirectionProfile);
+    method public default void onFanSpeedLevelProfileAvailable(androidx.car.app.hardware.climate.FanSpeedLevelProfile);
+    method public default void onHvacAcProfileAvailable(androidx.car.app.hardware.climate.HvacAcProfile);
+    method public default void onHvacAutoModeProfileAvailable(androidx.car.app.hardware.climate.HvacAutoModeProfile);
+    method public default void onHvacAutoRecirculationProfileAvailable(androidx.car.app.hardware.climate.HvacAutoRecirculationProfile);
+    method public default void onHvacDualModeProfileAvailable(androidx.car.app.hardware.climate.HvacDualModeProfile);
+    method public default void onHvacMaxAcModeProfileAvailable(androidx.car.app.hardware.climate.HvacMaxAcModeProfile);
+    method public default void onHvacPowerProfileAvailable(androidx.car.app.hardware.climate.HvacPowerProfile);
+    method public default void onHvacRecirculationProfileAvailable(androidx.car.app.hardware.climate.HvacRecirculationProfile);
+    method public default void onMaxDefrosterProfileAvailable(androidx.car.app.hardware.climate.MaxDefrosterProfile);
+    method public default void onSeatTemperatureLevelProfileAvailable(androidx.car.app.hardware.climate.SeatTemperatureProfile);
+    method public default void onSeatVentilationLevelProfileAvailable(androidx.car.app.hardware.climate.SeatVentilationProfile);
+    method public default void onSteeringWheelHeatProfileAvailable(androidx.car.app.hardware.climate.SteeringWheelHeatProfile);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimateStateCallback {
+    method public default void onCabinTemperatureStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method public default void onDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onElectricDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onFanDirectionStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public default void onFanSpeedLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public default void onHvacAcStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacAutoModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacAutoRecirculationStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacDualModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacMaxAcModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacPowerStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onHvacRecirculationStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onMaxDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public default void onSeatTemperatureLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public default void onSeatVentilationLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public default void onSteeringWheelHeatStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneMappingInfoProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class CarZoneMappingInfoProfile.Builder {
+    ctor public CarZoneMappingInfoProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.CarZoneMappingInfoProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class ClimateProfileRequest {
+    method public java.util.Set<java.lang.Integer!> getAllClimateProfiles();
+    method public java.util.List<androidx.car.app.hardware.climate.CarClimateFeature!> getClimateProfileFeatures();
+    field public static final int FEATURE_CABIN_TEMPERATURE = 4; // 0x4
+    field public static final int FEATURE_CAR_ZONE_MAPPING = 17; // 0x11
+    field public static final int FEATURE_FAN_DIRECTION = 6; // 0x6
+    field public static final int FEATURE_FAN_SPEED = 5; // 0x5
+    field public static final int FEATURE_HVAC_AC = 2; // 0x2
+    field public static final int FEATURE_HVAC_AUTO_MODE = 12; // 0xc
+    field public static final int FEATURE_HVAC_AUTO_RECIRCULATION = 11; // 0xb
+    field public static final int FEATURE_HVAC_DEFROSTER = 14; // 0xe
+    field public static final int FEATURE_HVAC_DUAL_MODE = 13; // 0xd
+    field public static final int FEATURE_HVAC_ELECTRIC_DEFROSTER = 16; // 0x10
+    field public static final int FEATURE_HVAC_MAX_AC = 3; // 0x3
+    field public static final int FEATURE_HVAC_MAX_DEFROSTER = 15; // 0xf
+    field public static final int FEATURE_HVAC_POWER = 1; // 0x1
+    field public static final int FEATURE_HVAC_RECIRCULATION = 10; // 0xa
+    field public static final int FEATURE_SEAT_TEMPERATURE_LEVEL = 7; // 0x7
+    field public static final int FEATURE_SEAT_VENTILATION_LEVEL = 8; // 0x8
+    field public static final int FEATURE_STEERING_WHEEL_HEAT = 9; // 0x9
+  }
+
+  public static final class ClimateProfileRequest.Builder {
+    ctor public ClimateProfileRequest.Builder();
+    method public androidx.car.app.hardware.climate.ClimateProfileRequest.Builder addClimateProfileFeatures(androidx.car.app.hardware.climate.CarClimateFeature!...);
+    method public androidx.car.app.hardware.climate.ClimateProfileRequest build();
+    method public androidx.car.app.hardware.climate.ClimateProfileRequest.Builder setAllClimateProfiles();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class ClimateStateRequest<T> {
+    method public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+    method public int getRequestedFeature();
+    method public T getRequestedValue();
+  }
+
+  public static final class ClimateStateRequest.Builder<T> {
+    ctor public ClimateStateRequest.Builder(int, T!);
+    method public androidx.car.app.hardware.climate.ClimateStateRequest.Builder<T!> addCarZones(androidx.car.app.hardware.common.CarZone);
+    method public androidx.car.app.hardware.climate.ClimateStateRequest<T!> build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class DefrosterProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class DefrosterProfile.Builder {
+    ctor public DefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.DefrosterProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class ElectricDefrosterProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class ElectricDefrosterProfile.Builder {
+    ctor public ElectricDefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.ElectricDefrosterProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class FanDirectionProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,java.util.Set<java.lang.Integer!>!> getCarZoneSetsToFanDirectionValues();
+  }
+
+  public static final class FanDirectionProfile.Builder {
+    ctor public FanDirectionProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,java.util.Set<java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.FanDirectionProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class FanSpeedLevelProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToFanSpeedLevelRanges();
+  }
+
+  public static final class FanSpeedLevelProfile.Builder {
+    ctor public FanSpeedLevelProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.FanSpeedLevelProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAcProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacAcProfile.Builder {
+    ctor public HvacAcProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacAcProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAutoModeProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacAutoModeProfile.Builder {
+    ctor public HvacAutoModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacAutoModeProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAutoRecirculationProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacAutoRecirculationProfile.Builder {
+    ctor public HvacAutoRecirculationProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacAutoRecirculationProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacDualModeProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacDualModeProfile.Builder {
+    ctor public HvacDualModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacDualModeProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacMaxAcModeProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacMaxAcModeProfile.Builder {
+    ctor public HvacMaxAcModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacMaxAcModeProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacPowerProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class HvacPowerProfile.Builder {
+    ctor public HvacPowerProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacPowerProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacRecirculationProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZones();
+  }
+
+  public static final class HvacRecirculationProfile.Builder {
+    ctor public HvacRecirculationProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.HvacRecirculationProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class MaxDefrosterProfile {
+    method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+  }
+
+  public static final class MaxDefrosterProfile.Builder {
+    ctor public MaxDefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+    method public androidx.car.app.hardware.climate.MaxDefrosterProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class RegisterClimateStateRequest {
+    method public java.util.List<androidx.car.app.hardware.climate.CarClimateFeature!> getClimateRegisterFeatures();
+  }
+
+  public static final class RegisterClimateStateRequest.Builder {
+    ctor public RegisterClimateStateRequest.Builder(boolean);
+    method public androidx.car.app.hardware.climate.RegisterClimateStateRequest.Builder addClimateRegisterFeatures(androidx.car.app.hardware.climate.CarClimateFeature!...);
+    method public androidx.car.app.hardware.climate.RegisterClimateStateRequest build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SeatTemperatureProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSeatTemperatureValues();
+  }
+
+  public static final class SeatTemperatureProfile.Builder {
+    ctor public SeatTemperatureProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.SeatTemperatureProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SeatVentilationProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSeatVentilationValues();
+  }
+
+  public static final class SeatVentilationProfile.Builder {
+    ctor public SeatVentilationProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.SeatVentilationProfile build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SteeringWheelHeatProfile {
+    method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSteeringWheelHeatValues();
+  }
+
+  public static final class SteeringWheelHeatProfile.Builder {
+    ctor public SteeringWheelHeatProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.climate.SteeringWheelHeatProfile build();
+  }
+
+}
+
+package androidx.car.app.hardware.common {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarSetOperationStatusCallback {
+    method public default void onSetCarClimateStateCabinTemperature(int);
+    method public default void onSetCarClimateStateDefroster(int);
+    method public default void onSetCarClimateStateElectricDefroster(int);
+    method public default void onSetCarClimateStateFanDirection(int);
+    method public default void onSetCarClimateStateFanSpeedLevel(int);
+    method public default void onSetCarClimateStateHvacAc(int);
+    method public default void onSetCarClimateStateHvacAutoMode(int);
+    method public default void onSetCarClimateStateHvacAutoRecirculation(int);
+    method public default void onSetCarClimateStateHvacDualMode(int);
+    method public default void onSetCarClimateStateHvacMaxAcMode(int);
+    method public default void onSetCarClimateStateHvacPower(int);
+    method public default void onSetCarClimateStateHvacRecirculation(int);
+    method public default void onSetCarClimateStateMaxDefroster(int);
+    method public default void onSetCarClimateStateSeatTemperatureLevel(int);
+    method public default void onSetCarClimateStateSeatVentilationLevel(int);
+    method public default void onSetCarClimateStateSteeringWheelHeat(int);
+    method public static String toString(int);
+    field public static final int OPERATION_STATUS_FEATURE_SETTING_NOT_ALLOWED = 4; // 0x4
+    field public static final int OPERATION_STATUS_FEATURE_TEMPORARILY_UNAVAILABLE = 3; // 0x3
+    field public static final int OPERATION_STATUS_FEATURE_UNIMPLEMENTED = 1; // 0x1
+    field public static final int OPERATION_STATUS_FEATURE_UNSUPPORTED = 2; // 0x2
+    field public static final int OPERATION_STATUS_ILLEGAL_CAR_HARDWARE_STATE = 7; // 0x7
+    field public static final int OPERATION_STATUS_INSUFFICIENT_PERMISSION = 6; // 0x6
+    field public static final int OPERATION_STATUS_SUCCESS = 0; // 0x0
+    field public static final int OPERATION_STATUS_UNSUPPORTED_VALUE = 5; // 0x5
+    field public static final int OPERATION_STATUS_UPDATE_TIMEOUT = 8; // 0x8
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarUnit {
+    method public static String toString(int);
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int IMPERIAL_GALLON = 204; // 0xcc
+    field public static final int KILOMETER = 3; // 0x3
+    field public static final int KILOMETERS_PER_HOUR = 102; // 0x66
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int LITER = 202; // 0xca
+    field public static final int METER = 2; // 0x2
+    field public static final int METERS_PER_SEC = 101; // 0x65
+    field public static final int MILE = 4; // 0x4
+    field public static final int MILES_PER_HOUR = 103; // 0x67
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int MILLILITER = 201; // 0xc9
+    field public static final int MILLIMETER = 1; // 0x1
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int US_GALLON = 203; // 0xcb
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarValue<T> {
+    ctor public CarValue(T?, long, int);
+    ctor @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public CarValue(T?, long, int, java.util.List<androidx.car.app.hardware.common.CarZone!>);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+    method public int getStatus();
+    method public long getTimestampMillis();
+    method public T? getValue();
+    field public static final int STATUS_SUCCESS = 1; // 0x1
+    field public static final int STATUS_UNAVAILABLE = 3; // 0x3
+    field public static final int STATUS_UNIMPLEMENTED = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class CarZone {
+    method public int getColumn();
+    method public int getRow();
+    field public static final int CAR_ZONE_COLUMN_ALL = 16; // 0x10
+    field public static final int CAR_ZONE_COLUMN_CENTER = 48; // 0x30
+    field public static final int CAR_ZONE_COLUMN_DRIVER = 80; // 0x50
+    field public static final int CAR_ZONE_COLUMN_LEFT = 32; // 0x20
+    field public static final int CAR_ZONE_COLUMN_PASSENGER = 96; // 0x60
+    field public static final int CAR_ZONE_COLUMN_RIGHT = 64; // 0x40
+    field public static final androidx.car.app.hardware.common.CarZone CAR_ZONE_GLOBAL;
+    field public static final int CAR_ZONE_ROW_ALL = 0; // 0x0
+    field public static final int CAR_ZONE_ROW_EXCLUDE_FIRST = 4; // 0x4
+    field public static final int CAR_ZONE_ROW_FIRST = 1; // 0x1
+    field public static final int CAR_ZONE_ROW_SECOND = 2; // 0x2
+    field public static final int CAR_ZONE_ROW_THIRD = 3; // 0x3
+  }
+
+  public static final class CarZone.Builder {
+    ctor public CarZone.Builder();
+    method public androidx.car.app.hardware.common.CarZone build();
+    method public androidx.car.app.hardware.common.CarZone.Builder setColumn(int);
+    method public androidx.car.app.hardware.common.CarZone.Builder setRow(int);
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public interface OnCarDataAvailableListener<T> {
+    method public void onCarDataAvailable(T);
+  }
+
+}
+
+package androidx.car.app.hardware.info {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Accelerometer {
+    ctor public Accelerometer(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getForces();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarHardwareLocation {
+    ctor public CarHardwareLocation(androidx.car.app.hardware.common.CarValue<android.location.Location!>);
+    method public androidx.car.app.hardware.common.CarValue<android.location.Location!> getLocation();
+  }
+
+  @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarInfo {
+    method public void addEnergyLevelListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyLevel!>);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void addEvStatusListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EvStatus!>);
+    method public void addMileageListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Mileage!>);
+    method public void addSpeedListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Speed!>);
+    method public void addTollListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.TollCard!>);
+    method public void fetchEnergyProfile(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyProfile!>);
+    method public void fetchModel(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Model!>);
+    method public void removeEnergyLevelListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyLevel!>);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void removeEvStatusListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EvStatus!>);
+    method public void removeMileageListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Mileage!>);
+    method public void removeSpeedListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Speed!>);
+    method public void removeTollListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.TollCard!>);
+  }
+
+  @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarSensors {
+    method public void addAccelerometerListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Accelerometer!>);
+    method public void addCarHardwareLocationListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.CarHardwareLocation!>);
+    method public void addCompassListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Compass!>);
+    method public void addGyroscopeListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Gyroscope!>);
+    method public void removeAccelerometerListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Accelerometer!>);
+    method public void removeCarHardwareLocationListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.CarHardwareLocation!>);
+    method public void removeCompassListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Compass!>);
+    method public void removeGyroscopeListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Gyroscope!>);
+    field public static final int UPDATE_RATE_FASTEST = 3; // 0x3
+    field public static final int UPDATE_RATE_NORMAL = 1; // 0x1
+    field public static final int UPDATE_RATE_UI = 2; // 0x2
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Compass {
+    ctor public Compass(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getOrientations();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyLevel {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getBatteryPercent();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getDistanceDisplayUnit();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEnergyIsLow();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getFuelPercent();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getFuelVolumeDisplayUnit();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getRangeRemainingMeters();
+  }
+
+  public static final class EnergyLevel.Builder {
+    ctor public EnergyLevel.Builder();
+    method public androidx.car.app.hardware.info.EnergyLevel build();
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setBatteryPercent(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setDistanceDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setEnergyIsLow(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setFuelPercent(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.hardware.info.EnergyLevel.Builder setFuelVolumeDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public androidx.car.app.hardware.info.EnergyLevel.Builder setRangeRemainingMeters(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyProfile {
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getEvConnectorTypes();
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getFuelTypes();
+    field public static final int EVCONNECTOR_TYPE_CHADEMO = 3; // 0x3
+    field public static final int EVCONNECTOR_TYPE_COMBO_1 = 4; // 0x4
+    field public static final int EVCONNECTOR_TYPE_COMBO_2 = 5; // 0x5
+    field public static final int EVCONNECTOR_TYPE_GBT = 9; // 0x9
+    field public static final int EVCONNECTOR_TYPE_GBT_DC = 10; // 0xa
+    field public static final int EVCONNECTOR_TYPE_J1772 = 1; // 0x1
+    field public static final int EVCONNECTOR_TYPE_MENNEKES = 2; // 0x2
+    field public static final int EVCONNECTOR_TYPE_OTHER = 101; // 0x65
+    field public static final int EVCONNECTOR_TYPE_SCAME = 11; // 0xb
+    field public static final int EVCONNECTOR_TYPE_TESLA_HPWC = 7; // 0x7
+    field public static final int EVCONNECTOR_TYPE_TESLA_ROADSTER = 6; // 0x6
+    field public static final int EVCONNECTOR_TYPE_TESLA_SUPERCHARGER = 8; // 0x8
+    field public static final int EVCONNECTOR_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int FUEL_TYPE_BIODIESEL = 5; // 0x5
+    field public static final int FUEL_TYPE_CNG = 8; // 0x8
+    field public static final int FUEL_TYPE_DIESEL_1 = 3; // 0x3
+    field public static final int FUEL_TYPE_DIESEL_2 = 4; // 0x4
+    field public static final int FUEL_TYPE_E85 = 6; // 0x6
+    field public static final int FUEL_TYPE_ELECTRIC = 10; // 0xa
+    field public static final int FUEL_TYPE_HYDROGEN = 11; // 0xb
+    field public static final int FUEL_TYPE_LEADED = 2; // 0x2
+    field public static final int FUEL_TYPE_LNG = 9; // 0x9
+    field public static final int FUEL_TYPE_LPG = 7; // 0x7
+    field public static final int FUEL_TYPE_OTHER = 12; // 0xc
+    field public static final int FUEL_TYPE_UNKNOWN = 0; // 0x0
+    field public static final int FUEL_TYPE_UNLEADED = 1; // 0x1
+  }
+
+  public static final class EnergyProfile.Builder {
+    ctor public EnergyProfile.Builder();
+    method public androidx.car.app.hardware.info.EnergyProfile build();
+    method public androidx.car.app.hardware.info.EnergyProfile.Builder setEvConnectorTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
+    method public androidx.car.app.hardware.info.EnergyProfile.Builder setFuelTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi public class EvStatus {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEvChargePortConnected();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEvChargePortOpen();
+  }
+
+  public static final class EvStatus.Builder {
+    ctor public EvStatus.Builder();
+    method public androidx.car.app.hardware.info.EvStatus build();
+    method public androidx.car.app.hardware.info.EvStatus.Builder setEvChargePortConnected(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+    method public androidx.car.app.hardware.info.EvStatus.Builder setEvChargePortOpen(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Gyroscope {
+    ctor public Gyroscope(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+    method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getRotations();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Mileage {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getDistanceDisplayUnit();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getOdometerMeters();
+  }
+
+  public static final class Mileage.Builder {
+    ctor public Mileage.Builder();
+    method public androidx.car.app.hardware.info.Mileage build();
+    method public androidx.car.app.hardware.info.Mileage.Builder setDistanceDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+    method public androidx.car.app.hardware.info.Mileage.Builder setOdometerMeters(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Model {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.String!> getManufacturer();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.String!> getName();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getYear();
+  }
+
+  public static final class Model.Builder {
+    ctor public Model.Builder();
+    method public androidx.car.app.hardware.info.Model build();
+    method public androidx.car.app.hardware.info.Model.Builder setManufacturer(androidx.car.app.hardware.common.CarValue<java.lang.String!>);
+    method public androidx.car.app.hardware.info.Model.Builder setName(androidx.car.app.hardware.common.CarValue<java.lang.String!>);
+    method public androidx.car.app.hardware.info.Model.Builder setYear(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Speed {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getDisplaySpeedMetersPerSecond();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getRawSpeedMetersPerSecond();
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getSpeedDisplayUnit();
+  }
+
+  public static final class Speed.Builder {
+    ctor public Speed.Builder();
+    method public androidx.car.app.hardware.info.Speed build();
+    method public androidx.car.app.hardware.info.Speed.Builder setDisplaySpeedMetersPerSecond(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method public androidx.car.app.hardware.info.Speed.Builder setRawSpeedMetersPerSecond(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+    method public androidx.car.app.hardware.info.Speed.Builder setSpeedDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class TollCard {
+    method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getCardState();
+    field public static final int TOLLCARD_STATE_INVALID = 2; // 0x2
+    field public static final int TOLLCARD_STATE_NOT_INSERTED = 3; // 0x3
+    field public static final int TOLLCARD_STATE_UNKNOWN = 0; // 0x0
+    field public static final int TOLLCARD_STATE_VALID = 1; // 0x1
+  }
+
+  public static final class TollCard.Builder {
+    ctor public TollCard.Builder();
+    method public androidx.car.app.hardware.info.TollCard build();
+    method public androidx.car.app.hardware.info.TollCard.Builder setCardState(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+  }
+
+}
+
+package androidx.car.app.managers {
+
+  public interface Manager {
+  }
+
+}
+
+package androidx.car.app.media {
+
+  @androidx.car.app.annotations.RequiresCarApi(5) public interface CarAudioCallback {
+    method public void onStopRecording();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public class CarAudioCallbackDelegate {
+    method public void onStopRecording();
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(5) public abstract class CarAudioRecord {
+    method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public static androidx.car.app.media.CarAudioRecord create(androidx.car.app.CarContext);
+    method public int read(byte[], int, int);
+    method public void startRecording();
+    method public void stopRecording();
+    field public static final int AUDIO_CONTENT_BUFFER_SIZE = 512; // 0x200
+    field public static final String AUDIO_CONTENT_MIME = "audio/l16";
+    field public static final int AUDIO_CONTENT_SAMPLING_RATE = 16000; // 0x3e80
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class OpenMicrophoneRequest {
+    method public androidx.car.app.media.CarAudioCallbackDelegate getCarAudioCallbackDelegate();
+  }
+
+  public static final class OpenMicrophoneRequest.Builder {
+    ctor public OpenMicrophoneRequest.Builder(androidx.car.app.media.CarAudioCallback);
+    method public androidx.car.app.media.OpenMicrophoneRequest build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class OpenMicrophoneResponse {
+    method public androidx.car.app.media.CarAudioCallbackDelegate getCarAudioCallback();
+    method public java.io.InputStream getCarMicrophoneInputStream();
+  }
+
+  public static final class OpenMicrophoneResponse.Builder {
+    ctor public OpenMicrophoneResponse.Builder(androidx.car.app.media.CarAudioCallback);
+    method public androidx.car.app.media.OpenMicrophoneResponse build();
+    method public androidx.car.app.media.OpenMicrophoneResponse.Builder setCarMicrophoneDescriptor(android.os.ParcelFileDescriptor);
+  }
+
+}
+
+package androidx.car.app.mediaextensions {
+
+  public final class MetadataExtras {
+    field public static final String KEY_CONTENT_FORMAT_DARK_MODE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_DARK_MODE_LARGE_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_DARK_MODE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_DARK_MODE_SMALL_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_LIGHT_MODE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_LIGHT_MODE_LARGE_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_LIGHT_MODE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_LIGHT_MODE_SMALL_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI";
+    field public static final String KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI";
+    field public static final String KEY_DESCRIPTION_LINK_MEDIA_ID = "androidx.car.app.mediaextensions.KEY_DESCRIPTION_LINK_MEDIA_ID";
+    field public static final String KEY_IMMERSIVE_AUDIO = "androidx.car.app.mediaextensions.KEY_IMMERSIVE_AUDIO";
+    field public static final String KEY_SUBTITLE_LINK_MEDIA_ID = "androidx.car.app.mediaextensions.KEY_SUBTITLE_LINK_MEDIA_ID";
+  }
+
+}
+
+package androidx.car.app.messaging {
+
+  @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class MessagingServiceConstants {
+    field public static final String ACTION_HANDLE_CAR_MESSAGING = "androidx.car.app.messaging.action.HANDLE_CAR_MESSAGING";
+  }
+
+}
+
+package androidx.car.app.messaging.model {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class CarMessage {
+    method public androidx.car.app.model.CarText? getBody();
+    method public String? getMultimediaMimeType();
+    method public android.net.Uri? getMultimediaUri();
+    method public long getReceivedTimeEpochMillis();
+    method public androidx.core.app.Person? getSender();
+    method public boolean isRead();
+  }
+
+  public static final class CarMessage.Builder {
+    ctor public CarMessage.Builder();
+    method public androidx.car.app.messaging.model.CarMessage build();
+    method public androidx.car.app.messaging.model.CarMessage.Builder setBody(androidx.car.app.model.CarText?);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setMultimediaMimeType(String?);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setMultimediaUri(android.net.Uri?);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setRead(boolean);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setReceivedTimeEpochMillis(long);
+    method public androidx.car.app.messaging.model.CarMessage.Builder setSender(androidx.core.app.Person?);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi public interface ConversationCallback {
+    method public void onMarkAsRead();
+    method public void onTextReply(String);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public interface ConversationCallbackDelegate {
+    method public void sendMarkAsRead(androidx.car.app.OnDoneCallback);
+    method public void sendTextReply(String, androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class ConversationItem implements androidx.car.app.model.Item {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.messaging.model.ConversationCallbackDelegate getConversationCallbackDelegate();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public String getId();
+    method public java.util.List<androidx.car.app.messaging.model.CarMessage!> getMessages();
+    method public androidx.core.app.Person getSelf();
+    method public androidx.car.app.model.CarText getTitle();
+    method public boolean isGroupConversation();
+  }
+
+  public static final class ConversationItem.Builder {
+    ctor public ConversationItem.Builder();
+    ctor public ConversationItem.Builder(androidx.car.app.messaging.model.ConversationItem);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.messaging.model.ConversationItem build();
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setConversationCallback(androidx.car.app.messaging.model.ConversationCallback);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setGroupConversation(boolean);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setId(String);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setMessages(java.util.List<androidx.car.app.messaging.model.CarMessage!>);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setSelf(androidx.core.app.Person);
+    method public androidx.car.app.messaging.model.ConversationItem.Builder setTitle(androidx.car.app.model.CarText);
+  }
+
+}
+
+package androidx.car.app.model {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Action {
+    method public androidx.car.app.model.CarColor? getBackgroundColor();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public int getFlags();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public int getType();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+    method public boolean isStandard();
+    method public static String typeToString(int);
+    field public static final androidx.car.app.model.Action APP_ICON;
+    field public static final androidx.car.app.model.Action BACK;
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.Action COMPOSE_MESSAGE;
+    field @androidx.car.app.annotations.RequiresCarApi(5) public static final int FLAG_DEFAULT = 4; // 0x4
+    field @androidx.car.app.annotations.RequiresCarApi(5) public static final int FLAG_IS_PERSISTENT = 2; // 0x2
+    field @androidx.car.app.annotations.RequiresCarApi(4) public static final int FLAG_PRIMARY = 1; // 0x1
+    field public static final androidx.car.app.model.Action PAN;
+    field public static final int TYPE_APP_ICON = 65538; // 0x10002
+    field public static final int TYPE_BACK = 65539; // 0x10003
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int TYPE_COMPOSE_MESSAGE = 65541; // 0x10005
+    field public static final int TYPE_CUSTOM = 1; // 0x1
+    field public static final int TYPE_PAN = 65540; // 0x10004
+  }
+
+  public static final class Action.Builder {
+    ctor public Action.Builder();
+    ctor @androidx.car.app.annotations.RequiresCarApi(2) public Action.Builder(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Action build();
+    method public androidx.car.app.model.Action.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Action.Builder setEnabled(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.Action.Builder setFlags(int);
+    method public androidx.car.app.model.Action.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Action.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+    method public androidx.car.app.model.Action.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.Action.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ActionStrip {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.Action? getFirstActionOfType(int);
+  }
+
+  public static final class ActionStrip.Builder {
+    ctor public ActionStrip.Builder();
+    method public androidx.car.app.model.ActionStrip.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.ActionStrip build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class Alert {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.AlertCallbackDelegate? getCallbackDelegate();
+    method public long getDurationMillis();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public int getId();
+    method public androidx.car.app.model.CarText? getSubtitle();
+    method public androidx.car.app.model.CarText getTitle();
+  }
+
+  public static final class Alert.Builder {
+    ctor public Alert.Builder(int, androidx.car.app.model.CarText, long);
+    method public androidx.car.app.model.Alert.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Alert build();
+    method public androidx.car.app.model.Alert.Builder setCallback(androidx.car.app.model.AlertCallback);
+    method public androidx.car.app.model.Alert.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Alert.Builder setSubtitle(androidx.car.app.model.CarText);
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallback {
+    method public void onCancel(int);
+    method public void onDismiss();
+    field public static final int REASON_NOT_SUPPORTED = 3; // 0x3
+    field public static final int REASON_TIMEOUT = 1; // 0x1
+    field public static final int REASON_USER_ACTION = 2; // 0x2
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallbackDelegate {
+    method public void sendCancel(int, androidx.car.app.OnDoneCallback);
+    method public void sendDismiss(androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class Badge {
+    method public androidx.car.app.model.CarColor? getBackgroundColor();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public boolean hasDot();
+  }
+
+  public static final class Badge.Builder {
+    ctor public Badge.Builder();
+    method public androidx.car.app.model.Badge build();
+    method public androidx.car.app.model.Badge.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.model.Badge.Builder setHasDot(boolean);
+    method public androidx.car.app.model.Badge.Builder setIcon(androidx.car.app.model.CarIcon);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarColor {
+    method public static androidx.car.app.model.CarColor createCustom(@ColorInt int, @ColorInt int);
+    method @ColorInt public int getColor();
+    method @ColorInt public int getColorDark();
+    method public int getType();
+    field public static final androidx.car.app.model.CarColor BLUE;
+    field public static final androidx.car.app.model.CarColor DEFAULT;
+    field public static final androidx.car.app.model.CarColor GREEN;
+    field public static final androidx.car.app.model.CarColor PRIMARY;
+    field public static final androidx.car.app.model.CarColor RED;
+    field public static final androidx.car.app.model.CarColor SECONDARY;
+    field public static final int TYPE_BLUE = 6; // 0x6
+    field public static final int TYPE_CUSTOM = 0; // 0x0
+    field public static final int TYPE_DEFAULT = 1; // 0x1
+    field public static final int TYPE_GREEN = 5; // 0x5
+    field public static final int TYPE_PRIMARY = 2; // 0x2
+    field public static final int TYPE_RED = 4; // 0x4
+    field public static final int TYPE_SECONDARY = 3; // 0x3
+    field public static final int TYPE_YELLOW = 7; // 0x7
+    field public static final androidx.car.app.model.CarColor YELLOW;
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarIcon {
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
+    method public androidx.car.app.model.CarColor? getTint();
+    method public int getType();
+    field public static final androidx.car.app.model.CarIcon ALERT;
+    field public static final androidx.car.app.model.CarIcon APP_ICON;
+    field public static final androidx.car.app.model.CarIcon BACK;
+    field @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.CarIcon COMPOSE_MESSAGE;
+    field public static final androidx.car.app.model.CarIcon ERROR;
+    field @androidx.car.app.annotations.RequiresCarApi(2) public static final androidx.car.app.model.CarIcon PAN;
+    field public static final int TYPE_ALERT = 4; // 0x4
+    field public static final int TYPE_APP_ICON = 5; // 0x5
+    field public static final int TYPE_BACK = 3; // 0x3
+    field public static final int TYPE_COMPOSE_MESSAGE = 8; // 0x8
+    field public static final int TYPE_CUSTOM = 1; // 0x1
+    field public static final int TYPE_ERROR = 6; // 0x6
+    field public static final int TYPE_PAN = 7; // 0x7
+  }
+
+  public static final class CarIcon.Builder {
+    ctor public CarIcon.Builder(androidx.car.app.model.CarIcon);
+    ctor public CarIcon.Builder(androidx.core.graphics.drawable.IconCompat);
+    method public androidx.car.app.model.CarIcon build();
+    method public androidx.car.app.model.CarIcon.Builder setTint(androidx.car.app.model.CarColor);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarIconSpan extends androidx.car.app.model.CarSpan {
+    method public static androidx.car.app.model.CarIconSpan create(androidx.car.app.model.CarIcon);
+    method public static androidx.car.app.model.CarIconSpan create(androidx.car.app.model.CarIcon, int);
+    method public int getAlignment();
+    method public androidx.car.app.model.CarIcon getIcon();
+    field public static final int ALIGN_BASELINE = 1; // 0x1
+    field public static final int ALIGN_BOTTOM = 0; // 0x0
+    field public static final int ALIGN_CENTER = 2; // 0x2
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarLocation {
+    method public static androidx.car.app.model.CarLocation create(android.location.Location);
+    method public static androidx.car.app.model.CarLocation create(double, double);
+    method public double getLatitude();
+    method public double getLongitude();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public class CarSpan extends android.text.style.CharacterStyle {
+    ctor public CarSpan();
+    method public void updateDrawState(android.text.TextPaint);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarText {
+    method public static androidx.car.app.model.CarText create(CharSequence);
+    method public java.util.List<java.lang.CharSequence!> getVariants();
+    method public boolean isEmpty();
+    method public static boolean isNullOrEmpty(androidx.car.app.model.CarText?);
+    method public CharSequence toCharSequence();
+  }
+
+  @SuppressCompatibility public static final class CarText.Builder {
+    ctor public CarText.Builder(CharSequence);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.CarText.Builder addVariant(CharSequence);
+    method public androidx.car.app.model.CarText build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(2) public final class ClickableSpan extends androidx.car.app.model.CarSpan {
+    method public static androidx.car.app.model.ClickableSpan create(androidx.car.app.model.OnClickListener);
+    method public androidx.car.app.model.OnClickDelegate getOnClickDelegate();
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public interface Content {
+    method public String getContentId();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DateTimeWithZone {
+    method @RequiresApi(26) public static androidx.car.app.model.DateTimeWithZone create(java.time.ZonedDateTime);
+    method public static androidx.car.app.model.DateTimeWithZone create(long, @IntRange(from=0xffff02e0, to=64800) int, String);
+    method public static androidx.car.app.model.DateTimeWithZone create(long, java.util.TimeZone);
+    method public long getTimeSinceEpochMillis();
+    method public int getZoneOffsetSeconds();
+    method public String? getZoneShortName();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Distance {
+    method public static androidx.car.app.model.Distance create(double, int);
+    method public double getDisplayDistance();
+    method public int getDisplayUnit();
+    field public static final int UNIT_FEET = 6; // 0x6
+    field public static final int UNIT_KILOMETERS = 2; // 0x2
+    field public static final int UNIT_KILOMETERS_P1 = 3; // 0x3
+    field public static final int UNIT_METERS = 1; // 0x1
+    field public static final int UNIT_MILES = 4; // 0x4
+    field public static final int UNIT_MILES_P1 = 5; // 0x5
+    field public static final int UNIT_YARDS = 7; // 0x7
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DistanceSpan extends androidx.car.app.model.CarSpan {
+    method public static androidx.car.app.model.DistanceSpan create(androidx.car.app.model.Distance);
+    method public androidx.car.app.model.Distance getDistance();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DurationSpan extends androidx.car.app.model.CarSpan {
+    method @RequiresApi(26) public static androidx.car.app.model.DurationSpan create(java.time.Duration);
+    method public static androidx.car.app.model.DurationSpan create(long);
+    method public long getDurationSeconds();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ForegroundCarColorSpan extends androidx.car.app.model.CarSpan {
+    method public static androidx.car.app.model.ForegroundCarColorSpan create(androidx.car.app.model.CarColor);
+    method public androidx.car.app.model.CarColor getColor();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class GridItem implements androidx.car.app.model.Item {
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.Badge? getBadge();
+    method public androidx.car.app.model.CarIcon? getImage();
+    method public int getImageType();
+    method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+    method public androidx.car.app.model.CarText? getText();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+    field public static final int IMAGE_TYPE_ICON = 1; // 0x1
+    field public static final int IMAGE_TYPE_LARGE = 2; // 0x2
+  }
+
+  public static final class GridItem.Builder {
+    ctor public GridItem.Builder();
+    method public androidx.car.app.model.GridItem build();
+    method public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, androidx.car.app.model.Badge);
+    method public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, int);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, int, androidx.car.app.model.Badge);
+    method public androidx.car.app.model.GridItem.Builder setLoading(boolean);
+    method public androidx.car.app.model.GridItem.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+    method public androidx.car.app.model.GridItem.Builder setText(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.GridItem.Builder setText(CharSequence);
+    method public androidx.car.app.model.GridItem.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.GridItem.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class GridTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemImageShape();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemSize();
+    method public androidx.car.app.model.ItemList? getSingleList();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_CIRCLE = 2; // 0x2
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_UNSET = 1; // 0x1
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_LARGE = 4; // 0x4
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_MEDIUM = 2; // 0x2
+    field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_SMALL = 1; // 0x1
+  }
+
+  public static final class GridTemplate.Builder {
+    ctor public GridTemplate.Builder();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.GridTemplate build();
+    method public androidx.car.app.model.GridTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.GridTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemImageShape(@SuppressCompatibility int);
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemSize(@SuppressCompatibility int);
+    method public androidx.car.app.model.GridTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.GridTemplate.Builder setSingleList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.model.GridTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class Header {
+    method public java.util.List<androidx.car.app.model.Action!> getEndHeaderActions();
+    method public androidx.car.app.model.Action? getStartHeaderAction();
+    method public androidx.car.app.model.CarText? getTitle();
+  }
+
+  public static final class Header.Builder {
+    ctor public Header.Builder();
+    method public androidx.car.app.model.Header.Builder addEndHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Header build();
+    method public androidx.car.app.model.Header.Builder setStartHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Header.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.Header.Builder setTitle(CharSequence);
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public interface InputCallback {
+    method public default void onInputSubmitted(String);
+    method public default void onInputTextChanged(String);
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public interface InputCallbackDelegate {
+    method public void sendInputSubmitted(String, androidx.car.app.OnDoneCallback);
+    method public void sendInputTextChanged(String, androidx.car.app.OnDoneCallback);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface Item {
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ItemList {
+    method public java.util.List<androidx.car.app.model.Item!> getItems();
+    method public androidx.car.app.model.CarText? getNoItemsMessage();
+    method public androidx.car.app.model.OnItemVisibilityChangedDelegate? getOnItemVisibilityChangedDelegate();
+    method public androidx.car.app.model.OnSelectedDelegate? getOnSelectedDelegate();
+    method public int getSelectedIndex();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ItemList.Builder toBuilder();
+  }
+
+  public static final class ItemList.Builder {
+    ctor public ItemList.Builder();
+    method public androidx.car.app.model.ItemList.Builder addItem(androidx.car.app.model.Item);
+    method public androidx.car.app.model.ItemList build();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ItemList.Builder clearItems();
+    method public androidx.car.app.model.ItemList.Builder setNoItemsMessage(CharSequence);
+    method public androidx.car.app.model.ItemList.Builder setOnItemsVisibilityChangedListener(androidx.car.app.model.ItemList.OnItemVisibilityChangedListener);
+    method public androidx.car.app.model.ItemList.Builder setOnSelectedListener(androidx.car.app.model.ItemList.OnSelectedListener);
+    method public androidx.car.app.model.ItemList.Builder setSelectedIndex(@IntRange(from=0) int);
+  }
+
+  public static interface ItemList.OnItemVisibilityChangedListener {
+    method public void onItemVisibilityChanged(int, int);
+  }
+
+  public static interface ItemList.OnSelectedListener {
+    method public void onSelected(int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ListTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public java.util.List<androidx.car.app.model.SectionedItemList!> getSectionedLists();
+    method public androidx.car.app.model.ItemList? getSingleList();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder toBuilder();
+  }
+
+  public static final class ListTemplate.Builder {
+    ctor public ListTemplate.Builder();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.ListTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.ListTemplate.Builder addSectionedList(androidx.car.app.model.SectionedItemList);
+    method public androidx.car.app.model.ListTemplate build();
+    method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder clearSectionedLists();
+    method public androidx.car.app.model.ListTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.ListTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.ListTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.ListTemplate.Builder setSingleList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.model.ListTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class LongMessageTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.CarText getMessage();
+    method public androidx.car.app.model.CarText? getTitle();
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public static final class LongMessageTemplate.Builder {
+    ctor public LongMessageTemplate.Builder(CharSequence);
+    method public androidx.car.app.model.LongMessageTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.LongMessageTemplate build();
+    method public androidx.car.app.model.LongMessageTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.LongMessageTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.LongMessageTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class MessageTemplate implements androidx.car.app.model.Template {
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.CarText? getDebugMessage();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public androidx.car.app.model.CarText getMessage();
+    method public androidx.car.app.model.CarText? getTitle();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public boolean isLoading();
+  }
+
+  public static final class MessageTemplate.Builder {
+    ctor public MessageTemplate.Builder(androidx.car.app.model.CarText);
+    ctor public MessageTemplate.Builder(CharSequence);
+    method public androidx.car.app.model.MessageTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.MessageTemplate build();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.MessageTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.MessageTemplate.Builder setDebugMessage(String);
+    method public androidx.car.app.model.MessageTemplate.Builder setDebugMessage(Throwable);
+    method public androidx.car.app.model.MessageTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.MessageTemplate.Builder setIcon(androidx.car.app.model.CarIcon);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.MessageTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.MessageTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Metadata {
+    method public androidx.car.app.model.Place? getPlace();
+    field public static final androidx.car.app.model.Metadata EMPTY_METADATA;
+  }
+
+  public static final class Metadata.Builder {
+    ctor public Metadata.Builder();
+    ctor public Metadata.Builder(androidx.car.app.model.Metadata);
+    method public androidx.car.app.model.Metadata build();
+    method public androidx.car.app.model.Metadata.Builder setPlace(androidx.car.app.model.Place);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnCheckedChangeDelegate {
+    method public void sendCheckedChange(boolean, androidx.car.app.OnDoneCallback);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnClickDelegate {
+    method public boolean isParkedOnly();
+    method public void sendClick(androidx.car.app.OnDoneCallback);
+  }
+
+  public interface OnClickListener {
+    method public void onClick();
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface OnContentRefreshDelegate {
+    method public void sendContentRefreshRequested(androidx.car.app.OnDoneCallback);
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(5) public interface OnContentRefreshListener {
+    method public void onContentRefreshRequested();
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnItemVisibilityChangedDelegate {
+    method public void sendItemVisibilityChanged(int, int, androidx.car.app.OnDoneCallback);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface OnSelectedDelegate {
+    method public void sendSelected(int, androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Pane {
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.CarIcon? getImage();
+    method public java.util.List<androidx.car.app.model.Row!> getRows();
+    method public boolean isLoading();
+  }
+
+  public static final class Pane.Builder {
+    ctor public Pane.Builder();
+    method public androidx.car.app.model.Pane.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Pane.Builder addRow(androidx.car.app.model.Row);
+    method public androidx.car.app.model.Pane build();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.Pane.Builder setImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Pane.Builder setLoading(boolean);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PaneTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.Pane getPane();
+    method public androidx.car.app.model.CarText? getTitle();
+  }
+
+  public static final class PaneTemplate.Builder {
+    ctor public PaneTemplate.Builder(androidx.car.app.model.Pane);
+    method public androidx.car.app.model.PaneTemplate build();
+    method public androidx.car.app.model.PaneTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.PaneTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.PaneTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ParkedOnlyOnClickListener implements androidx.car.app.model.OnClickListener {
+    method public static androidx.car.app.model.ParkedOnlyOnClickListener create(androidx.car.app.model.OnClickListener);
+    method public void onClick();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Place {
+    method public androidx.car.app.model.CarLocation getLocation();
+    method public androidx.car.app.model.PlaceMarker? getMarker();
+  }
+
+  public static final class Place.Builder {
+    ctor public Place.Builder(androidx.car.app.model.CarLocation);
+    ctor public Place.Builder(androidx.car.app.model.Place);
+    method public androidx.car.app.model.Place build();
+    method public androidx.car.app.model.Place.Builder setMarker(androidx.car.app.model.PlaceMarker);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceListMapTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Place? getAnchor();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.OnContentRefreshDelegate? getOnContentRefreshDelegate();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isCurrentLocationEnabled();
+    method public boolean isLoading();
+  }
+
+  public static final class PlaceListMapTemplate.Builder {
+    ctor public PlaceListMapTemplate.Builder();
+    method public androidx.car.app.model.PlaceListMapTemplate build();
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setAnchor(androidx.car.app.model.Place);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setCurrentLocationEnabled(boolean);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setLoading(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.PlaceListMapTemplate.Builder setOnContentRefreshListener(androidx.car.app.model.OnContentRefreshListener);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.PlaceListMapTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceMarker {
+    method public androidx.car.app.model.CarColor? getColor();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public int getIconType();
+    method public androidx.car.app.model.CarText? getLabel();
+    field public static final int TYPE_ICON = 0; // 0x0
+    field public static final int TYPE_IMAGE = 1; // 0x1
+  }
+
+  public static final class PlaceMarker.Builder {
+    ctor public PlaceMarker.Builder();
+    method public androidx.car.app.model.PlaceMarker build();
+    method public androidx.car.app.model.PlaceMarker.Builder setColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.model.PlaceMarker.Builder setIcon(androidx.car.app.model.CarIcon, int);
+    method public androidx.car.app.model.PlaceMarker.Builder setLabel(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Row implements androidx.car.app.model.Item {
+    method @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.CarIcon? getImage();
+    method public androidx.car.app.model.Metadata? getMetadata();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public int getNumericDecoration();
+    method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+    method public int getRowImageType();
+    method public java.util.List<androidx.car.app.model.CarText!> getTexts();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public androidx.car.app.model.Toggle? getToggle();
+    method public boolean isBrowsable();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+    method public androidx.car.app.model.Row row();
+    method public CharSequence yourBoat();
+    field public static final int IMAGE_TYPE_ICON = 4; // 0x4
+    field public static final int IMAGE_TYPE_LARGE = 2; // 0x2
+    field public static final int IMAGE_TYPE_SMALL = 1; // 0x1
+    field public static final int NO_DECORATION = -1; // 0xffffffff
+  }
+
+  public static final class Row.Builder {
+    ctor public Row.Builder();
+    method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.Row.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Row.Builder addText(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.Row.Builder addText(CharSequence);
+    method public androidx.car.app.model.Row build();
+    method public androidx.car.app.model.Row.Builder setBrowsable(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Row.Builder setEnabled(boolean);
+    method public androidx.car.app.model.Row.Builder setImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Row.Builder setImage(androidx.car.app.model.CarIcon, int);
+    method public androidx.car.app.model.Row.Builder setMetadata(androidx.car.app.model.Metadata);
+    method @IntRange(from=0) @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.Row.Builder setNumericDecoration(int);
+    method public androidx.car.app.model.Row.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+    method public androidx.car.app.model.Row.Builder setTitle(androidx.car.app.model.CarText);
+    method public androidx.car.app.model.Row.Builder setTitle(CharSequence);
+    method public androidx.car.app.model.Row.Builder setToggle(androidx.car.app.model.Toggle);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface SearchCallbackDelegate {
+    method public void sendSearchSubmitted(String, androidx.car.app.OnDoneCallback);
+    method public void sendSearchTextChanged(String, androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SearchTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public String? getInitialSearchText();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method public androidx.car.app.model.SearchCallbackDelegate getSearchCallbackDelegate();
+    method public String? getSearchHint();
+    method public boolean isLoading();
+    method public boolean isShowKeyboardByDefault();
+  }
+
+  public static final class SearchTemplate.Builder {
+    ctor public SearchTemplate.Builder(androidx.car.app.model.SearchTemplate.SearchCallback);
+    method public androidx.car.app.model.SearchTemplate build();
+    method public androidx.car.app.model.SearchTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.SearchTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.SearchTemplate.Builder setInitialSearchText(String);
+    method public androidx.car.app.model.SearchTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.model.SearchTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.SearchTemplate.Builder setSearchHint(String);
+    method public androidx.car.app.model.SearchTemplate.Builder setShowKeyboardByDefault(boolean);
+  }
+
+  public static interface SearchTemplate.SearchCallback {
+    method public default void onSearchSubmitted(String);
+    method public default void onSearchTextChanged(String);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SectionedItemList {
+    method public static androidx.car.app.model.SectionedItemList create(androidx.car.app.model.ItemList, CharSequence);
+    method public androidx.car.app.model.CarText getHeader();
+    method public androidx.car.app.model.ItemList getItemList();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public final class Tab implements androidx.car.app.model.Content {
+    method public String getContentId();
+    method public androidx.car.app.model.CarIcon getIcon();
+    method public androidx.car.app.model.CarText getTitle();
+  }
+
+  public static final class Tab.Builder {
+    ctor public Tab.Builder();
+    ctor public Tab.Builder(androidx.car.app.model.Tab);
+    method public androidx.car.app.model.Tab build();
+    method public androidx.car.app.model.Tab.Builder setContentId(String);
+    method public androidx.car.app.model.Tab.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.model.Tab.Builder setTitle(CharSequence);
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public interface TabCallbackDelegate {
+    method public void sendTabSelected(String, androidx.car.app.OnDoneCallback);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class TabContents implements androidx.car.app.model.Content {
+    method public String getContentId();
+    method public androidx.car.app.model.Template getTemplate();
+    field public static final String CONTENT_ID = "TAB_CONTENTS_CONTENT_ID";
+  }
+
+  public static final class TabContents.Builder {
+    ctor public TabContents.Builder(androidx.car.app.model.Template);
+    method public androidx.car.app.model.TabContents build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class TabTemplate implements androidx.car.app.model.Template {
+    method public String getActiveTabContentId();
+    method public androidx.car.app.model.Action getHeaderAction();
+    method public androidx.car.app.model.TabCallbackDelegate getTabCallbackDelegate();
+    method public androidx.car.app.model.TabContents getTabContents();
+    method public java.util.List<androidx.car.app.model.Tab!> getTabs();
+    method public boolean isLoading();
+  }
+
+  public static final class TabTemplate.Builder {
+    ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate);
+    ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate.TabCallback);
+    method public androidx.car.app.model.TabTemplate.Builder addTab(androidx.car.app.model.Tab);
+    method public androidx.car.app.model.TabTemplate build();
+    method public androidx.car.app.model.TabTemplate.Builder setActiveTabContentId(String);
+    method public androidx.car.app.model.TabTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.TabTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.TabTemplate.Builder setTabContents(androidx.car.app.model.TabContents);
+  }
+
+  public static interface TabTemplate.TabCallback {
+    method public default void onTabSelected(String);
+  }
+
+  @androidx.car.app.annotations.CarProtocol public interface Template {
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TemplateInfo {
+    ctor public TemplateInfo(Class<? extends androidx.car.app.model.Template>, String);
+    method public Class<? extends androidx.car.app.model.Template> getTemplateClass();
+    method public String getTemplateId();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TemplateWrapper {
+    method public static androidx.car.app.model.TemplateWrapper copyOf(androidx.car.app.model.TemplateWrapper);
+    method public int getCurrentTaskStep();
+    method public String getId();
+    method public androidx.car.app.model.Template getTemplate();
+    method public java.util.List<androidx.car.app.model.TemplateInfo!> getTemplateInfosForScreenStack();
+    method public boolean isRefresh();
+    method public void setCurrentTaskStep(int);
+    method public void setId(String);
+    method public void setRefresh(boolean);
+    method public void setTemplate(androidx.car.app.model.Template);
+    method public static androidx.car.app.model.TemplateWrapper wrap(androidx.car.app.model.Template);
+    method public static androidx.car.app.model.TemplateWrapper wrap(androidx.car.app.model.Template, String);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Toggle {
+    method public androidx.car.app.model.OnCheckedChangeDelegate getOnCheckedChangeDelegate();
+    method public boolean isChecked();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+  }
+
+  public static final class Toggle.Builder {
+    ctor public Toggle.Builder(androidx.car.app.model.Toggle.OnCheckedChangeListener);
+    method public androidx.car.app.model.Toggle build();
+    method public androidx.car.app.model.Toggle.Builder setChecked(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Toggle.Builder setEnabled(boolean);
+  }
+
+  public static interface Toggle.OnCheckedChangeListener {
+    method public void onCheckedChange(boolean);
+  }
+
+}
+
+package androidx.car.app.model.signin {
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class InputSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+    method public androidx.car.app.model.CarText? getDefaultValue();
+    method public androidx.car.app.model.CarText? getErrorMessage();
+    method public androidx.car.app.model.CarText? getHint();
+    method public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
+    method public int getInputType();
+    method public int getKeyboardType();
+    method public boolean isShowKeyboardByDefault();
+    field public static final int INPUT_TYPE_DEFAULT = 1; // 0x1
+    field public static final int INPUT_TYPE_PASSWORD = 2; // 0x2
+    field public static final int KEYBOARD_DEFAULT = 1; // 0x1
+    field public static final int KEYBOARD_EMAIL = 2; // 0x2
+    field public static final int KEYBOARD_NUMBER = 4; // 0x4
+    field public static final int KEYBOARD_PHONE = 3; // 0x3
+  }
+
+  public static final class InputSignInMethod.Builder {
+    ctor public InputSignInMethod.Builder(androidx.car.app.model.InputCallback);
+    method public androidx.car.app.model.signin.InputSignInMethod build();
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setDefaultValue(String);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setErrorMessage(CharSequence);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setHint(CharSequence);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setInputType(int);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setKeyboardType(int);
+    method public androidx.car.app.model.signin.InputSignInMethod.Builder setShowKeyboardByDefault(boolean);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class PinSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+    ctor public PinSignInMethod(CharSequence);
+    method public androidx.car.app.model.CarText getPinCode();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class ProviderSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+    ctor public ProviderSignInMethod(androidx.car.app.model.Action);
+    method public androidx.car.app.model.Action getAction();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(4) public final class QRCodeSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+    ctor public QRCodeSignInMethod(android.net.Uri);
+    method public android.net.Uri getUri();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class SignInTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public java.util.List<androidx.car.app.model.Action!> getActions();
+    method public androidx.car.app.model.CarText? getAdditionalText();
+    method public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.CarText? getInstructions();
+    method public androidx.car.app.model.signin.SignInTemplate.SignInMethod getSignInMethod();
+    method public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+  }
+
+  @androidx.car.app.annotations.RequiresCarApi(2) public static final class SignInTemplate.Builder {
+    ctor public SignInTemplate.Builder(androidx.car.app.model.signin.SignInTemplate.SignInMethod);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder addAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.signin.SignInTemplate build();
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setAdditionalText(CharSequence);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setInstructions(CharSequence);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.model.signin.SignInTemplate.Builder setTitle(CharSequence);
+  }
+
+  public static interface SignInTemplate.SignInMethod {
+  }
+
+}
+
+package androidx.car.app.navigation {
+
+  public class NavigationManager implements androidx.car.app.managers.Manager {
+    method @MainThread public void clearNavigationManagerCallback();
+    method @MainThread public void navigationEnded();
+    method @MainThread public void navigationStarted();
+    method @MainThread public void setNavigationManagerCallback(androidx.car.app.navigation.NavigationManagerCallback);
+    method @MainThread public void setNavigationManagerCallback(java.util.concurrent.Executor, androidx.car.app.navigation.NavigationManagerCallback);
+    method @MainThread public void updateTrip(androidx.car.app.navigation.model.Trip);
+  }
+
+  public interface NavigationManagerCallback {
+    method public default void onAutoDriveEnabled();
+    method public default void onStopNavigation();
+  }
+
+}
+
+package androidx.car.app.navigation.model {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Destination {
+    method public androidx.car.app.model.CarText? getAddress();
+    method public androidx.car.app.model.CarIcon? getImage();
+    method public androidx.car.app.model.CarText? getName();
+  }
+
+  public static final class Destination.Builder {
+    ctor public Destination.Builder();
+    method public androidx.car.app.navigation.model.Destination build();
+    method public androidx.car.app.navigation.model.Destination.Builder setAddress(CharSequence);
+    method public androidx.car.app.navigation.model.Destination.Builder setImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.Destination.Builder setName(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Lane {
+    method public java.util.List<androidx.car.app.navigation.model.LaneDirection!> getDirections();
+  }
+
+  public static final class Lane.Builder {
+    ctor public Lane.Builder();
+    method public androidx.car.app.navigation.model.Lane.Builder addDirection(androidx.car.app.navigation.model.LaneDirection);
+    method public androidx.car.app.navigation.model.Lane build();
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class LaneDirection {
+    method public static androidx.car.app.navigation.model.LaneDirection create(int, boolean);
+    method public int getShape();
+    method public boolean isRecommended();
+    field public static final int SHAPE_NORMAL_LEFT = 5; // 0x5
+    field public static final int SHAPE_NORMAL_RIGHT = 6; // 0x6
+    field public static final int SHAPE_SHARP_LEFT = 7; // 0x7
+    field public static final int SHAPE_SHARP_RIGHT = 8; // 0x8
+    field public static final int SHAPE_SLIGHT_LEFT = 3; // 0x3
+    field public static final int SHAPE_SLIGHT_RIGHT = 4; // 0x4
+    field public static final int SHAPE_STRAIGHT = 2; // 0x2
+    field public static final int SHAPE_UNKNOWN = 1; // 0x1
+    field public static final int SHAPE_U_TURN_LEFT = 9; // 0x9
+    field public static final int SHAPE_U_TURN_RIGHT = 10; // 0xa
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Maneuver {
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public int getRoundaboutExitAngle();
+    method public int getRoundaboutExitNumber();
+    method public int getType();
+    field public static final int TYPE_DEPART = 1; // 0x1
+    field public static final int TYPE_DESTINATION = 39; // 0x27
+    field public static final int TYPE_DESTINATION_LEFT = 41; // 0x29
+    field public static final int TYPE_DESTINATION_RIGHT = 42; // 0x2a
+    field public static final int TYPE_DESTINATION_STRAIGHT = 40; // 0x28
+    field public static final int TYPE_FERRY_BOAT = 37; // 0x25
+    field public static final int TYPE_FERRY_BOAT_LEFT = 47; // 0x2f
+    field public static final int TYPE_FERRY_BOAT_RIGHT = 48; // 0x30
+    field public static final int TYPE_FERRY_TRAIN = 38; // 0x26
+    field public static final int TYPE_FERRY_TRAIN_LEFT = 49; // 0x31
+    field public static final int TYPE_FERRY_TRAIN_RIGHT = 50; // 0x32
+    field public static final int TYPE_FORK_LEFT = 25; // 0x19
+    field public static final int TYPE_FORK_RIGHT = 26; // 0x1a
+    field public static final int TYPE_KEEP_LEFT = 3; // 0x3
+    field public static final int TYPE_KEEP_RIGHT = 4; // 0x4
+    field public static final int TYPE_MERGE_LEFT = 27; // 0x1b
+    field public static final int TYPE_MERGE_RIGHT = 28; // 0x1c
+    field public static final int TYPE_MERGE_SIDE_UNSPECIFIED = 29; // 0x1d
+    field public static final int TYPE_NAME_CHANGE = 2; // 0x2
+    field public static final int TYPE_OFF_RAMP_NORMAL_LEFT = 23; // 0x17
+    field public static final int TYPE_OFF_RAMP_NORMAL_RIGHT = 24; // 0x18
+    field public static final int TYPE_OFF_RAMP_SLIGHT_LEFT = 21; // 0x15
+    field public static final int TYPE_OFF_RAMP_SLIGHT_RIGHT = 22; // 0x16
+    field public static final int TYPE_ON_RAMP_NORMAL_LEFT = 15; // 0xf
+    field public static final int TYPE_ON_RAMP_NORMAL_RIGHT = 16; // 0x10
+    field public static final int TYPE_ON_RAMP_SHARP_LEFT = 17; // 0x11
+    field public static final int TYPE_ON_RAMP_SHARP_RIGHT = 18; // 0x12
+    field public static final int TYPE_ON_RAMP_SLIGHT_LEFT = 13; // 0xd
+    field public static final int TYPE_ON_RAMP_SLIGHT_RIGHT = 14; // 0xe
+    field public static final int TYPE_ON_RAMP_U_TURN_LEFT = 19; // 0x13
+    field public static final int TYPE_ON_RAMP_U_TURN_RIGHT = 20; // 0x14
+    field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW = 34; // 0x22
+    field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE = 35; // 0x23
+    field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW = 32; // 0x20
+    field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE = 33; // 0x21
+    field public static final int TYPE_ROUNDABOUT_ENTER_CCW = 45; // 0x2d
+    field public static final int TYPE_ROUNDABOUT_ENTER_CW = 43; // 0x2b
+    field public static final int TYPE_ROUNDABOUT_EXIT_CCW = 46; // 0x2e
+    field public static final int TYPE_ROUNDABOUT_EXIT_CW = 44; // 0x2c
+    field public static final int TYPE_STRAIGHT = 36; // 0x24
+    field public static final int TYPE_TURN_NORMAL_LEFT = 7; // 0x7
+    field public static final int TYPE_TURN_NORMAL_RIGHT = 8; // 0x8
+    field public static final int TYPE_TURN_SHARP_LEFT = 9; // 0x9
+    field public static final int TYPE_TURN_SHARP_RIGHT = 10; // 0xa
+    field public static final int TYPE_TURN_SLIGHT_LEFT = 5; // 0x5
+    field public static final int TYPE_TURN_SLIGHT_RIGHT = 6; // 0x6
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_U_TURN_LEFT = 11; // 0xb
+    field public static final int TYPE_U_TURN_RIGHT = 12; // 0xc
+  }
+
+  public static final class Maneuver.Builder {
+    ctor public Maneuver.Builder(int);
+    method public androidx.car.app.navigation.model.Maneuver build();
+    method public androidx.car.app.navigation.model.Maneuver.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.Maneuver.Builder setRoundaboutExitAngle(@IntRange(from=1, to=360) int);
+    method public androidx.car.app.navigation.model.Maneuver.Builder setRoundaboutExitNumber(@IntRange(from=1) int);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class MapController {
+    method public androidx.car.app.model.ActionStrip? getMapActionStrip();
+    method public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+  }
+
+  public static final class MapController.Builder {
+    ctor public MapController.Builder();
+    method public androidx.car.app.navigation.model.MapController build();
+    method public androidx.car.app.navigation.model.MapController.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.MapController.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class MapTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Header? getHeader();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method public androidx.car.app.navigation.model.MapController? getMapController();
+    method public androidx.car.app.model.Pane? getPane();
+  }
+
+  public static final class MapTemplate.Builder {
+    ctor public MapTemplate.Builder();
+    method public androidx.car.app.navigation.model.MapTemplate build();
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setHeader(androidx.car.app.model.Header);
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setMapController(androidx.car.app.navigation.model.MapController);
+    method public androidx.car.app.navigation.model.MapTemplate.Builder setPane(androidx.car.app.model.Pane);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public final class MapWithContentTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.Template? getContentTemplate();
+    method public androidx.car.app.navigation.model.MapController? getMapController();
+    method public boolean isLoading();
+  }
+
+  public static final class MapWithContentTemplate.Builder {
+    ctor public MapWithContentTemplate.Builder();
+    method public androidx.car.app.navigation.model.MapWithContentTemplate build();
+    method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setContentTemplate(androidx.car.app.model.Template);
+    method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setLoading(boolean);
+    method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setMapController(androidx.car.app.navigation.model.MapController);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class MessageInfo implements androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo {
+    method public androidx.car.app.model.CarIcon? getImage();
+    method public androidx.car.app.model.CarText? getText();
+    method public androidx.car.app.model.CarText? getTitle();
+  }
+
+  public static final class MessageInfo.Builder {
+    ctor public MessageInfo.Builder(androidx.car.app.model.CarText);
+    ctor public MessageInfo.Builder(CharSequence);
+    method public androidx.car.app.navigation.model.MessageInfo build();
+    method public androidx.car.app.navigation.model.MessageInfo.Builder setImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.MessageInfo.Builder setText(androidx.car.app.model.CarText);
+    method public androidx.car.app.navigation.model.MessageInfo.Builder setText(CharSequence);
+    method public androidx.car.app.navigation.model.MessageInfo.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class NavigationTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method public androidx.car.app.model.CarColor? getBackgroundColor();
+    method public androidx.car.app.navigation.model.TravelEstimate? getDestinationTravelEstimate();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+    method public androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo? getNavigationInfo();
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+    method @Deprecated @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.Toggle? getPanModeToggle();
+  }
+
+  public static final class NavigationTemplate.Builder {
+    ctor public NavigationTemplate.Builder();
+    method public androidx.car.app.navigation.model.NavigationTemplate build();
+    method public androidx.car.app.navigation.model.NavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.NavigationTemplate.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.navigation.model.NavigationTemplate.Builder setDestinationTravelEstimate(androidx.car.app.navigation.model.TravelEstimate);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.NavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.NavigationTemplate.Builder setNavigationInfo(androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo);
+    method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.NavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+  }
+
+  public static interface NavigationTemplate.NavigationInfo {
+  }
+
+  @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(2) public interface PanModeDelegate {
+    method public void sendPanModeChanged(boolean, androidx.car.app.OnDoneCallback);
+  }
+
+  public interface PanModeListener {
+    method public void onPanModeChanged(boolean);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceListNavigationTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Header? getHeader();
+    method @Deprecated public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+    method public androidx.car.app.model.OnContentRefreshDelegate? getOnContentRefreshDelegate();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+    method @Deprecated public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+  }
+
+  public static final class PlaceListNavigationTemplate.Builder {
+    ctor public PlaceListNavigationTemplate.Builder();
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate build();
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setHeader(androidx.car.app.model.Header);
+    method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setLoading(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setOnContentRefreshListener(androidx.car.app.model.OnContentRefreshListener);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+    method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setTitle(androidx.car.app.model.CarText);
+    method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class RoutePreviewNavigationTemplate implements androidx.car.app.model.Template {
+    method public androidx.car.app.model.ActionStrip? getActionStrip();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Header? getHeader();
+    method @Deprecated public androidx.car.app.model.Action? getHeaderAction();
+    method public androidx.car.app.model.ItemList? getItemList();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+    method public androidx.car.app.model.Action? getNavigateAction();
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+    method @Deprecated public androidx.car.app.model.CarText? getTitle();
+    method public boolean isLoading();
+  }
+
+  public static final class RoutePreviewNavigationTemplate.Builder {
+    ctor public RoutePreviewNavigationTemplate.Builder();
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate build();
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setHeader(androidx.car.app.model.Header);
+    method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setLoading(boolean);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+    method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setNavigateAction(androidx.car.app.model.Action);
+    method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+    method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setTitle(androidx.car.app.model.CarText);
+    method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setTitle(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class RoutingInfo implements androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo {
+    method public androidx.car.app.model.Distance? getCurrentDistance();
+    method public androidx.car.app.navigation.model.Step? getCurrentStep();
+    method public androidx.car.app.model.CarIcon? getJunctionImage();
+    method public androidx.car.app.navigation.model.Step? getNextStep();
+    method public boolean isLoading();
+  }
+
+  public static final class RoutingInfo.Builder {
+    ctor public RoutingInfo.Builder();
+    method public androidx.car.app.navigation.model.RoutingInfo build();
+    method public androidx.car.app.navigation.model.RoutingInfo.Builder setCurrentStep(androidx.car.app.navigation.model.Step, androidx.car.app.model.Distance);
+    method public androidx.car.app.navigation.model.RoutingInfo.Builder setJunctionImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.RoutingInfo.Builder setLoading(boolean);
+    method public androidx.car.app.navigation.model.RoutingInfo.Builder setNextStep(androidx.car.app.navigation.model.Step);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Step {
+    method public androidx.car.app.model.CarText? getCue();
+    method public java.util.List<androidx.car.app.navigation.model.Lane!> getLanes();
+    method public androidx.car.app.model.CarIcon? getLanesImage();
+    method public androidx.car.app.navigation.model.Maneuver? getManeuver();
+    method public androidx.car.app.model.CarText? getRoad();
+  }
+
+  public static final class Step.Builder {
+    ctor public Step.Builder();
+    ctor public Step.Builder(androidx.car.app.model.CarText);
+    ctor public Step.Builder(CharSequence);
+    method public androidx.car.app.navigation.model.Step.Builder addLane(androidx.car.app.navigation.model.Lane);
+    method public androidx.car.app.navigation.model.Step build();
+    method public androidx.car.app.navigation.model.Step.Builder setCue(CharSequence);
+    method public androidx.car.app.navigation.model.Step.Builder setLanesImage(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.navigation.model.Step.Builder setManeuver(androidx.car.app.navigation.model.Maneuver);
+    method public androidx.car.app.navigation.model.Step.Builder setRoad(CharSequence);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TravelEstimate {
+    method public androidx.car.app.model.DateTimeWithZone? getArrivalTimeAtDestination();
+    method public androidx.car.app.model.Distance? getRemainingDistance();
+    method public androidx.car.app.model.CarColor? getRemainingDistanceColor();
+    method public androidx.car.app.model.CarColor? getRemainingTimeColor();
+    method public long getRemainingTimeSeconds();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.CarIcon? getTripIcon();
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.CarText? getTripText();
+    field public static final long REMAINING_TIME_UNKNOWN = -1L; // 0xffffffffffffffffL
+  }
+
+  public static final class TravelEstimate.Builder {
+    ctor public TravelEstimate.Builder(androidx.car.app.model.Distance, androidx.car.app.model.DateTimeWithZone);
+    ctor @RequiresApi(26) public TravelEstimate.Builder(androidx.car.app.model.Distance, java.time.ZonedDateTime);
+    method public androidx.car.app.navigation.model.TravelEstimate build();
+    method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingDistanceColor(androidx.car.app.model.CarColor);
+    method @RequiresApi(26) public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTime(java.time.Duration);
+    method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTimeColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTimeSeconds(@IntRange(from=0xffffffff) long);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.TravelEstimate.Builder setTripIcon(androidx.car.app.model.CarIcon);
+    method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.TravelEstimate.Builder setTripText(androidx.car.app.model.CarText);
+  }
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Trip {
+    method public androidx.car.app.model.CarText? getCurrentRoad();
+    method public java.util.List<androidx.car.app.navigation.model.TravelEstimate!> getDestinationTravelEstimates();
+    method public java.util.List<androidx.car.app.navigation.model.Destination!> getDestinations();
+    method public java.util.List<androidx.car.app.navigation.model.TravelEstimate!> getStepTravelEstimates();
+    method public java.util.List<androidx.car.app.navigation.model.Step!> getSteps();
+    method public boolean isLoading();
+  }
+
+  public static final class Trip.Builder {
+    ctor public Trip.Builder();
+    method public androidx.car.app.navigation.model.Trip.Builder addDestination(androidx.car.app.navigation.model.Destination, androidx.car.app.navigation.model.TravelEstimate);
+    method public androidx.car.app.navigation.model.Trip.Builder addStep(androidx.car.app.navigation.model.Step, androidx.car.app.navigation.model.TravelEstimate);
+    method public androidx.car.app.navigation.model.Trip build();
+    method public androidx.car.app.navigation.model.Trip.Builder setCurrentRoad(CharSequence);
+    method public androidx.car.app.navigation.model.Trip.Builder setLoading(boolean);
+  }
+
+}
+
+package androidx.car.app.notification {
+
+  public final class CarAppExtender implements androidx.core.app.NotificationCompat.Extender {
+    ctor public CarAppExtender(android.app.Notification);
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+    method public java.util.List<android.app.Notification.Action!> getActions();
+    method public String? getChannelId();
+    method public androidx.car.app.model.CarColor? getColor();
+    method public android.app.PendingIntent? getContentIntent();
+    method public CharSequence? getContentText();
+    method public CharSequence? getContentTitle();
+    method public android.app.PendingIntent? getDeleteIntent();
+    method public int getImportance();
+    method public android.graphics.Bitmap? getLargeIcon();
+    method @DrawableRes public int getSmallIcon();
+    method public static boolean isExtended(android.app.Notification);
+  }
+
+  public static final class CarAppExtender.Builder {
+    ctor public CarAppExtender.Builder();
+    method public androidx.car.app.notification.CarAppExtender.Builder addAction(@DrawableRes int, CharSequence, android.app.PendingIntent);
+    method public androidx.car.app.notification.CarAppExtender build();
+    method public androidx.car.app.notification.CarAppExtender.Builder setChannelId(String);
+    method public androidx.car.app.notification.CarAppExtender.Builder setColor(androidx.car.app.model.CarColor);
+    method public androidx.car.app.notification.CarAppExtender.Builder setContentIntent(android.app.PendingIntent);
+    method public androidx.car.app.notification.CarAppExtender.Builder setContentText(CharSequence);
+    method public androidx.car.app.notification.CarAppExtender.Builder setContentTitle(CharSequence);
+    method public androidx.car.app.notification.CarAppExtender.Builder setDeleteIntent(android.app.PendingIntent);
+    method public androidx.car.app.notification.CarAppExtender.Builder setImportance(int);
+    method public androidx.car.app.notification.CarAppExtender.Builder setLargeIcon(android.graphics.Bitmap);
+    method public androidx.car.app.notification.CarAppExtender.Builder setSmallIcon(int);
+  }
+
+  public final class CarNotificationManager {
+    method public boolean areNotificationsEnabled();
+    method public void cancel(int);
+    method public void cancel(String?, int);
+    method public void cancelAll();
+    method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+    method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+    method public void createNotificationChannelGroups(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+    method public void createNotificationChannels(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+    method public void deleteNotificationChannel(String);
+    method public void deleteNotificationChannelGroup(String);
+    method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+    method public static androidx.car.app.notification.CarNotificationManager from(android.content.Context);
+    method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+    method public int getImportance();
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannel(String);
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannel(String, String);
+    method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroup(String);
+    method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroups();
+    method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannels();
+    method public void notify(int, androidx.core.app.NotificationCompat.Builder);
+    method public void notify(String?, int, androidx.core.app.NotificationCompat.Builder);
+  }
+
+  public final class CarPendingIntent {
+    method public static android.app.PendingIntent getCarApp(android.content.Context, int, android.content.Intent, int);
+  }
+
+}
+
+package androidx.car.app.serialization {
+
+  public final class Bundleable implements android.os.Parcelable {
+    method public static androidx.car.app.serialization.Bundleable create(Object) throws androidx.car.app.serialization.BundlerException;
+    method public int describeContents();
+    method public Object get() throws androidx.car.app.serialization.BundlerException;
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.car.app.serialization.Bundleable!> CREATOR;
+  }
+
+  public class BundlerException extends java.lang.Exception {
+    ctor public BundlerException(String?);
+    ctor public BundlerException(String?, Throwable);
+  }
+
+}
+
+package androidx.car.app.suggestion {
+
+  @androidx.car.app.annotations.RequiresCarApi(5) public class SuggestionManager implements androidx.car.app.managers.Manager {
+    method @MainThread public void updateSuggestions(java.util.List<androidx.car.app.suggestion.model.Suggestion!>);
+  }
+
+}
+
+package androidx.car.app.suggestion.model {
+
+  @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Suggestion {
+    method public android.app.PendingIntent? getAction();
+    method public androidx.car.app.model.CarIcon? getIcon();
+    method public String getIdentifier();
+    method public androidx.car.app.model.CarText? getSubtitle();
+    method public androidx.car.app.model.CarText getTitle();
+  }
+
+  public static final class Suggestion.Builder {
+    ctor public Suggestion.Builder();
+    method public androidx.car.app.suggestion.model.Suggestion build();
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setAction(android.app.PendingIntent);
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setIcon(androidx.car.app.model.CarIcon);
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setIdentifier(String);
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setSubtitle(CharSequence);
+    method public androidx.car.app.suggestion.model.Suggestion.Builder setTitle(CharSequence);
+  }
+
+}
+
+package androidx.car.app.validation {
+
+  public final class HostValidator {
+    method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getAllowedHosts();
+    method public boolean isValidHost(androidx.car.app.HostInfo);
+    field public static final androidx.car.app.validation.HostValidator ALLOW_ALL_HOSTS_VALIDATOR;
+    field public static final String TEMPLATE_RENDERER_PERMISSION = "android.car.permission.TEMPLATE_RENDERER";
+  }
+
+  public static final class HostValidator.Builder {
+    ctor public HostValidator.Builder(android.content.Context);
+    method public androidx.car.app.validation.HostValidator.Builder addAllowedHost(String, String);
+    method public androidx.car.app.validation.HostValidator.Builder addAllowedHosts(@ArrayRes int);
+    method public androidx.car.app.validation.HostValidator build();
+  }
+
+}
+
+package androidx.car.app.versioning {
+
+  public final class CarAppApiLevels {
+    method public static int getLatest();
+    method public static int getOldest();
+    field public static final int LEVEL_1 = 1; // 0x1
+    field public static final int LEVEL_2 = 2; // 0x2
+    field public static final int LEVEL_3 = 3; // 0x3
+    field public static final int LEVEL_4 = 4; // 0x4
+    field public static final int LEVEL_5 = 5; // 0x5
+    field public static final int LEVEL_6 = 6; // 0x6
+    field public static final int LEVEL_7 = 7; // 0x7
+  }
+
+}
+
diff --git a/compose/animation/animation/api/current.ignore b/compose/animation/animation/api/current.ignore
new file mode 100644
index 0000000..721c745
--- /dev/null
+++ b/compose/animation/animation/api/current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+AddedAbstractMethod: androidx.compose.animation.AnimatedContentTransitionScope#getContentAlignment():
+    Added method androidx.compose.animation.AnimatedContentTransitionScope.getContentAlignment()
diff --git a/compose/animation/animation/api/current.txt b/compose/animation/animation/api/current.txt
index f66083e..1d1e078 100644
--- a/compose/animation/animation/api/current.txt
+++ b/compose/animation/animation/api/current.txt
@@ -17,10 +17,14 @@
   }
 
   public sealed interface AnimatedContentTransitionScope<S> extends androidx.compose.animation.core.Transition.Segment<S> {
+    method public androidx.compose.ui.Alignment getContentAlignment();
     method public default androidx.compose.animation.ExitTransition getHold(androidx.compose.animation.ExitTransition.Companion);
+    method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.EnterTransition scaleInToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
+    method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.ExitTransition scaleOutToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
     method public androidx.compose.animation.EnterTransition slideIntoContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> initialOffset);
     method public androidx.compose.animation.ExitTransition slideOutOfContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> targetOffset);
     method public infix androidx.compose.animation.ContentTransform using(androidx.compose.animation.ContentTransform, androidx.compose.animation.SizeTransform? sizeTransform);
+    property public abstract androidx.compose.ui.Alignment contentAlignment;
   }
 
   @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public static final value class AnimatedContentTransitionScope.SlideDirection {
diff --git a/compose/animation/animation/api/restricted_current.ignore b/compose/animation/animation/api/restricted_current.ignore
new file mode 100644
index 0000000..721c745
--- /dev/null
+++ b/compose/animation/animation/api/restricted_current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+AddedAbstractMethod: androidx.compose.animation.AnimatedContentTransitionScope#getContentAlignment():
+    Added method androidx.compose.animation.AnimatedContentTransitionScope.getContentAlignment()
diff --git a/compose/animation/animation/api/restricted_current.txt b/compose/animation/animation/api/restricted_current.txt
index f66083e..1d1e078 100644
--- a/compose/animation/animation/api/restricted_current.txt
+++ b/compose/animation/animation/api/restricted_current.txt
@@ -17,10 +17,14 @@
   }
 
   public sealed interface AnimatedContentTransitionScope<S> extends androidx.compose.animation.core.Transition.Segment<S> {
+    method public androidx.compose.ui.Alignment getContentAlignment();
     method public default androidx.compose.animation.ExitTransition getHold(androidx.compose.animation.ExitTransition.Companion);
+    method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.EnterTransition scaleInToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
+    method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.ExitTransition scaleOutToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
     method public androidx.compose.animation.EnterTransition slideIntoContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> initialOffset);
     method public androidx.compose.animation.ExitTransition slideOutOfContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> targetOffset);
     method public infix androidx.compose.animation.ContentTransform using(androidx.compose.animation.ContentTransform, androidx.compose.animation.SizeTransform? sizeTransform);
+    property public abstract androidx.compose.ui.Alignment contentAlignment;
   }
 
   @androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public static final value class AnimatedContentTransitionScope.SlideDirection {
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/ContainerTransform.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/ContainerTransform.kt
new file mode 100644
index 0000000..e2bbcbd
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/ContainerTransform.kt
@@ -0,0 +1,246 @@
+/*
+ * 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.compose.animation.demos.layoutanimation
+
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.animateIntAsState
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.togetherWith
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Icon
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.RadioButton
+import androidx.compose.material.Text
+import androidx.compose.material.TextField
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.AccountCircle
+import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.rememberVectorPainter
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+
+@OptIn(ExperimentalAnimationApi::class)
+@Preview
+@Composable
+fun LocalContainerTransformDemo() {
+    Box(Modifier.fillMaxSize()) {
+        LazyColumn {
+            items(20) {
+                Box(
+                    Modifier
+                        .fillMaxWidth()
+                        .height(150.dp)
+                        .padding(15.dp)
+                        .background(MaterialTheme.colors.primary)
+                )
+            }
+        }
+    }
+    var selectedAlignment by remember { mutableStateOf(Alignment.Center) }
+    var contentScale by remember { mutableStateOf(ContentScale.FillWidth) }
+    Column(
+        Modifier.padding(top = 100.dp)
+    ) {
+        Column(
+            Modifier
+                .background(Color.LightGray, RoundedCornerShape(10.dp)),
+        ) {
+            Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+                RadioButton(
+                    selected = selectedAlignment == Alignment.TopStart,
+                    onClick = { selectedAlignment = Alignment.TopStart }
+                )
+                Text("TopStart", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = selectedAlignment == Alignment.TopCenter,
+                    onClick = { selectedAlignment = Alignment.TopCenter }
+                )
+                Text("TopCenter", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = selectedAlignment == Alignment.TopEnd,
+                    onClick = { selectedAlignment = Alignment.TopEnd }
+                )
+                Text("TopEnd", Modifier.padding(5.dp))
+            }
+            Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+                RadioButton(
+                    selected = selectedAlignment == Alignment.CenterStart,
+                    onClick = { selectedAlignment = Alignment.CenterStart }
+                )
+                Text("CenterStart", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = selectedAlignment == Alignment.Center,
+                    onClick = { selectedAlignment = Alignment.Center }
+                )
+                Text("Center", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = selectedAlignment == Alignment.CenterEnd,
+                    onClick = { selectedAlignment = Alignment.CenterEnd }
+                )
+                Text("CenterEnd", Modifier.padding(5.dp))
+            }
+            Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+                RadioButton(
+                    selected = selectedAlignment == Alignment.BottomStart,
+                    onClick = { selectedAlignment = Alignment.BottomStart }
+                )
+                Text("BottomStart", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = selectedAlignment == Alignment.BottomCenter,
+                    onClick = { selectedAlignment = Alignment.BottomCenter }
+                )
+                Text("BottomCenter", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = selectedAlignment == Alignment.BottomEnd,
+                    onClick = { selectedAlignment = Alignment.BottomEnd }
+                )
+                Text("BottomEnd", Modifier.padding(5.dp))
+            }
+        }
+        Column(
+            Modifier
+                .background(Color.Gray, RoundedCornerShape(10.dp)),
+        ) {
+            Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+                RadioButton(
+                    selected = contentScale == ContentScale.FillWidth,
+                    onClick = { contentScale = ContentScale.FillWidth }
+                )
+                Text("FillWidth", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = contentScale == ContentScale.FillHeight,
+                    onClick = { contentScale = ContentScale.FillHeight }
+                )
+                Text("FillHeight", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = contentScale == ContentScale.FillBounds,
+                    onClick = { contentScale = ContentScale.FillBounds }
+                )
+                Text("FillBounds", Modifier.padding(5.dp))
+            }
+            Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+                RadioButton(
+                    selected = contentScale == ContentScale.Crop,
+                    onClick = { contentScale = ContentScale.Crop }
+                )
+                Text("Crop", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = contentScale == ContentScale.Fit,
+                    onClick = { contentScale = ContentScale.Fit }
+                )
+                Text("Fit", Modifier.padding(5.dp))
+                RadioButton(
+                    selected = contentScale == ContentScale.Inside,
+                    onClick = { contentScale = ContentScale.Inside }
+                )
+                Text("Inside", Modifier.padding(5.dp))
+            }
+        }
+    }
+    Box(Modifier.fillMaxSize()) {
+        var target by remember { mutableStateOf(ContainerState.FAB) }
+        // Corner radius
+        val cr by animateIntAsState(if (target == ContainerState.FAB) 50 else 0)
+        val padding by animateDpAsState(if (target == ContainerState.FAB) 10.dp else 0.dp)
+        AnimatedContent(
+            target,
+            label = "",
+            transitionSpec = {
+                fadeIn(tween(200, delayMillis = 100)) +
+                    scaleInToFitContainer(selectedAlignment, contentScale) togetherWith
+                    fadeOut(tween(100)) + scaleOutToFitContainer(selectedAlignment, contentScale)
+            },
+            modifier = Modifier
+                .align(Alignment.BottomEnd)
+                .padding(padding)
+                .clip(RoundedCornerShape(cr))
+                .background(Color.White)
+        ) {
+            if (it == ContainerState.FAB) {
+                Icon(
+                    rememberVectorPainter(image = Icons.Default.Add),
+                    null,
+                    modifier = Modifier
+                        .clickable {
+                            target = ContainerState.FullScreen
+                        }
+                        .padding(20.dp))
+            } else {
+                Column(Modifier.fillMaxSize()) {
+                    Icon(
+                        rememberVectorPainter(image = Icons.Default.ArrowBack),
+                        null,
+                        modifier = Modifier
+                            .clickable {
+                                target = ContainerState.FAB
+                            }
+                            .padding(20.dp))
+                    Spacer(Modifier.height(60.dp))
+                    Text("Page Title", fontSize = 20.sp, modifier = Modifier.padding(20.dp))
+                    Spacer(
+                        Modifier
+                            .fillMaxWidth()
+                            .height(2.dp)
+                            .background(Color.LightGray)
+                    )
+                    Row(
+                        Modifier
+                            .fillMaxWidth()
+                            .padding(20.dp)
+                    ) {
+                        Icon(rememberVectorPainter(image = Icons.Default.AccountCircle), null)
+                        Spacer(Modifier.width(20.dp))
+                        TextField(value = "Account Name", onValueChange = {})
+                    }
+                }
+            }
+        }
+    }
+}
+
+private enum class ContainerState {
+    FAB,
+    FullScreen
+}
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
index 96a707a..707240c 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
@@ -33,7 +33,11 @@
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
+import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.drawscope.translate
 import androidx.compose.ui.layout.LookaheadScope
 import androidx.compose.ui.layout.Placeable
 import androidx.compose.ui.layout.intermediateLayout
@@ -54,6 +58,7 @@
         Spring.DampingRatioNoBouncy,
         Spring.StiffnessMediumLow
     ),
+    debug: Boolean = false,
     lookaheadScope: (closestLookaheadScope: LookaheadScope) -> LookaheadScope = { it }
 ) = composed {
 
@@ -68,6 +73,17 @@
     // When the measure block is invoked after lookahead pass, the lookahead size of the
     // child will be accessible as a parameter to the measure block.
     this
+        .drawWithContent {
+            drawContent()
+            if (debug) {
+                val offset = outerOffsetAnimation.target!! - outerOffsetAnimation.value!!
+                translate(
+                    offset.x.toFloat(), offset.y.toFloat()
+                ) {
+                    drawRect(Color.Black.copy(alpha = 0.5f), style = Stroke(10f))
+                }
+            }
+        }
         .intermediateLayout { measurable, constraints ->
             val (w, h) = outerSizeAnimation.updateTarget(
                 lookaheadSize,
@@ -85,6 +101,17 @@
                 }
         }
         .then(modifier)
+        .drawWithContent {
+            drawContent()
+            if (debug) {
+                val offset = offsetAnimation.target!! - offsetAnimation.value!!
+                translate(
+                    offset.x.toFloat(), offset.y.toFloat()
+                ) {
+                    drawRect(Color.Green.copy(alpha = 0.5f), style = Stroke(10f))
+                }
+            }
+        }
         .intermediateLayout { measurable, _ ->
             // When layout changes, the lookahead pass will calculate a new final size for the
             // child modifier. This lookahead size can be used to animate the size
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt
index adba4fa..35058df 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt
@@ -16,18 +16,26 @@
 
 package androidx.compose.animation.demos.lookahead
 
+import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowColumn
 import androidx.compose.foundation.layout.FlowRow
 import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.widthIn
 import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.layout.wrapContentWidth
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.Button
 import androidx.compose.material.Text
@@ -41,6 +49,8 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.LookaheadScope
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.tooling.preview.Preview
 import androidx.compose.ui.unit.dp
 
 @OptIn(ExperimentalComposeUiApi::class, ExperimentalLayoutApi::class)
@@ -135,6 +145,77 @@
     }
 }
 
+@OptIn(ExperimentalComposeUiApi::class, ExperimentalLayoutApi::class)
+@Preview
+@Composable
+fun NestedFlowRowDemo() {
+    LookaheadScope {
+        FlowRow(
+            modifier = Modifier.fillMaxSize(),
+            horizontalArrangement = Arrangement.Center,
+            verticalArrangement = Arrangement.Center,
+            maxItemsInEachRow = 3
+        ) {
+            var expanded by remember {
+                mutableStateOf(false)
+            }
+            Box(
+                modifier = Modifier
+                    .animateBounds(Modifier.widthIn(max = 600.dp))
+                    .background(Color.Red)
+            ) {
+                val height = animateDpAsState(targetValue = if (expanded) 500.dp else 300.dp)
+                Box(
+                    modifier = Modifier
+                        .animateBounds(
+                            Modifier
+                                .fillMaxWidth()
+                                .height(height.value)
+                        )
+                        .clickable {
+                            expanded = !expanded
+                        })
+            }
+
+            FlowColumn(Modifier.layout { measurable, constraints ->
+                measurable.measure(constraints).run {
+                    layout(width, height) {
+                        place(0, 0)
+                    }
+                }
+            }) {
+                Box(
+                    modifier = Modifier
+                        .size(200.dp)
+                        .animateBounds(
+                            Modifier
+                                .wrapContentWidth()
+                                .heightIn(min = 156.dp),
+                            debug = true
+
+                        )
+                        .background(Color.Blue)
+                ) {
+                    Box(modifier = Modifier.size(200.dp))
+                }
+                Box(
+                    modifier = Modifier
+                        .size(200.dp)
+                        .animateBounds(
+                            Modifier
+                                .wrapContentWidth()
+                                .heightIn(min = 156.dp),
+                            debug = true
+                        )
+                        .background(Color.Yellow)
+                ) {
+                    Box(modifier = Modifier.size(200.dp))
+                }
+            }
+        }
+    }
+}
+
 private val colors = listOf(
     Color(0xffff6f69),
     Color(0xffffcc5c),
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt
index f21c93f..f0e325b 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt
@@ -22,6 +22,7 @@
 import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection
 import androidx.compose.animation.ContentTransform
 import androidx.compose.animation.ExitTransition
+import androidx.compose.animation.ExperimentalAnimationApi
 import androidx.compose.animation.SizeTransform
 import androidx.compose.animation.core.animateDp
 import androidx.compose.animation.core.keyframes
@@ -54,6 +55,7 @@
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.draw.shadow
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
@@ -116,7 +118,8 @@
         Box(
             Modifier
                 .size(200.dp)
-                .background(Color(0xffffdb00)))
+                .background(Color(0xffffdb00))
+        )
     }
 
     @Composable
@@ -124,7 +127,8 @@
         Box(
             Modifier
                 .size(40.dp)
-                .background(Color(0xffff8100)))
+                .background(Color(0xffff8100))
+        )
     }
 
     @Composable
@@ -132,7 +136,8 @@
         Box(
             Modifier
                 .size(80.dp, 20.dp)
-                .background(Color(0xffff4400)))
+                .background(Color(0xffff4400))
+        )
     }
 
     var contentState: ContentState by remember { mutableStateOf(ContentState.Foo) }
@@ -304,6 +309,30 @@
     }
 }
 
+@OptIn(ExperimentalAnimationApi::class)
+@Suppress("UNUSED_VARIABLE")
+@Sampled
+@Composable
+fun ScaleInToFitContainerSample() {
+    // enum class CartState { Expanded, Collapsed }
+    // This is an example of scaling both the incoming content and outgoing content to fit in the
+    // animating container size while animating alpha.
+    val transitionSpec: AnimatedContentTransitionScope<CartState>.() -> ContentTransform = {
+        // Fade in while scaling the content.
+        fadeIn() + scaleInToFitContainer() togetherWith
+            // Fade out outgoing content while scaling it. It is important
+            // to combine `scaleOutToFitContainer` with another ExitTransition that defines
+            // a timeframe for the exit (such as fade/shrink/slide/Hold).
+            fadeOut() + scaleOutToFitContainer(
+                // Default alignment is the content alignment defined in AnimatedContent
+                Alignment.Center,
+                // Content will be scaled based on the height of the content. Default content
+                // scale is ContentScale.FillWidth.
+                ContentScale.FillHeight
+            )
+    }
+}
+
 private enum class CartState {
     Expanded,
     Collapsed
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
index 9540bd4..c6925f9 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:OptIn(ExperimentalAnimationApi::class)
+
 package androidx.compose.animation
 
 import androidx.compose.animation.core.InternalAnimationApi
@@ -41,11 +43,16 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.boundsInRoot
 import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.layout.onPlaced
 import androidx.compose.ui.layout.positionInRoot
 import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
@@ -54,6 +61,7 @@
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.round
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import com.google.common.truth.Truth.assertThat
@@ -656,6 +664,400 @@
         assertTrue(box2EnterFinished)
     }
 
+    @Test
+    fun testScaleToFitDefault() {
+        var target by mutableStateOf(1)
+        var box1Coords: LayoutCoordinates? = null
+        var box2Coords: LayoutCoordinates? = null
+        var box1Disposed = true
+        var box2Disposed = true
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                AnimatedContent(
+                    targetState = target,
+                    transitionSpec = {
+                        if (1 isTransitioningTo 2) {
+                            fadeIn(tween(300)) + scaleInToFitContainer() togetherWith
+                                scaleOutToFitContainer()
+                        } else {
+                            fadeIn() + scaleInToFitContainer() togetherWith
+                                fadeOut(tween(150))
+                        } using SizeTransform { initialSize, targetSize ->
+                            keyframes {
+                                durationMillis = 300
+                                initialSize at 100 with LinearEasing
+                                targetSize at 200 with LinearEasing
+                            }
+                        }
+                    }) {
+                    if (it == 1) {
+                        Box(
+                            Modifier
+                                .onPlaced {
+                                    box1Coords = it
+                                }
+                                .size(200.dp, 400.dp)) {
+                            DisposableEffect(key1 = Unit) {
+                                box1Disposed = false
+                                onDispose {
+                                    box1Disposed = true
+                                }
+                            }
+                        }
+                    } else {
+                        Box(
+                            Modifier
+                                .onPlaced { box2Coords = it }
+                                .size(100.dp, 50.dp)) {
+
+                            DisposableEffect(key1 = Unit) {
+                                box2Disposed = false
+                                onDispose {
+                                    box2Disposed = true
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        rule.waitForIdle()
+        rule.mainClock.autoAdvance = false
+        assertEquals(IntSize(200, 400), box1Coords?.size)
+        assertNull(box2Coords)
+
+        assertFalse(box1Disposed)
+        assertTrue(box2Disposed)
+
+        rule.runOnIdle {
+            // Start transition from 1 -> 2, size 200,400 -> 100,50
+            target = 2
+        }
+        rule.mainClock.advanceTimeByFrame()
+        rule.waitForIdle()
+
+        // Box1 doesn't have any other ExitTransition than scale, so it'll be disposed
+        // after a couple of frames
+        assertFalse(box1Disposed)
+        assertFalse(box2Disposed)
+
+        repeat(20) {
+            rule.mainClock.advanceTimeByFrame()
+
+            val playTime = 16 * it
+            val bounds2 = box2Coords?.boundsInRoot()
+            if (playTime <= 100) {
+                assertEquals(Rect(0f, 0f, 200f, 100f), bounds2)
+            } else if (playTime <= 200) {
+                val fraction = (playTime - 100) / 100f
+                val width = 200 * (1 - fraction) + 100 * fraction
+                // Since we are testing default behavior, the scaling is based on width.
+                val height = width / 100f * 50
+                assertEquals(Offset.Zero, bounds2?.topLeft)
+                assertEquals(width, bounds2?.width)
+                assertEquals(height, bounds2?.height)
+            } else {
+                assertEquals(Rect(0f, 0f, 100f, 50f), bounds2)
+            }
+        }
+
+        rule.runOnIdle {
+            // Start transition from false -> true, size 100, 50 -> 200,400
+            target = 1
+        }
+        rule.mainClock.advanceTimeByFrame()
+        rule.waitForIdle()
+
+        assertFalse(box1Disposed)
+        assertFalse(box2Disposed)
+
+        repeat(20) {
+            rule.mainClock.advanceTimeByFrame()
+            val playTime = 16 * it
+            val bounds = box1Coords?.boundsInRoot()
+            if (playTime <= 100) {
+                assertEquals(100f, bounds?.width)
+                assertFalse(box2Disposed)
+            } else if (playTime <= 150) {
+                val fraction = (playTime - 100) / 100f
+                val width = 100 * (1 - fraction) + 200 * fraction
+                // Since we are testing default behavior, the scaling is based on width.
+                assertEquals(Offset.Zero, bounds?.topLeft)
+                assertEquals(width, bounds?.width)
+            } else {
+                rule.waitForIdle()
+                assertThat(box2Disposed)
+            }
+        }
+    }
+
+    @Test
+    fun testScaleToFitCenterAlignment() {
+        var target by mutableStateOf(true)
+        var box1Coords: LayoutCoordinates? = null
+        var box2Coords: LayoutCoordinates? = null
+        var layoutDirection: LayoutDirection? = null
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                layoutDirection = LocalLayoutDirection.current
+                AnimatedContent(
+                    targetState = target,
+                    transitionSpec = {
+                        fadeIn() + scaleInToFitContainer(Alignment.Center) togetherWith
+                            fadeOut(tween(100)) using
+                            SizeTransform { _, _ ->
+                                tween(100, easing = LinearEasing)
+                            }
+                    }) {
+                    if (target) {
+                        Box(
+                            Modifier
+                                .onPlaced {
+                                    box1Coords = it
+                                }
+                                .size(200.dp, 400.dp))
+                    } else {
+                        Box(
+                            Modifier
+                                .onPlaced { box2Coords = it }
+                                .size(100.dp, 50.dp))
+                    }
+                }
+            }
+        }
+
+        rule.waitForIdle()
+        assertEquals(IntSize(200, 400), box1Coords?.size)
+        assertNull(box2Coords)
+
+        rule.runOnIdle {
+            // Start transition from true -> false, size 200,400 -> 100,50
+            target = false
+        }
+        rule.mainClock.advanceTimeByFrame()
+        repeat(10) {
+            rule.mainClock.advanceTimeByFrame()
+            val playTime = 16 * it
+            val bounds = box2Coords?.boundsInRoot()
+            assertNotNull(bounds)
+            val fraction = (playTime / 100f).coerceAtMost(1f)
+            val width = 200 * (1 - fraction) + 100 * fraction
+            val containerHeight = 400 * (1 - fraction) + 50 * fraction
+            // Since we are testing default behavior, the scaling is based on width.
+            val height = width / 100f * 50
+            assertEquals(width, bounds!!.width, 0.01f)
+            assertEquals(height, bounds.height, 0.01f)
+            val offset = Alignment.Center.align(
+                IntSize(width.roundToInt(), height.roundToInt()),
+                IntSize(width.roundToInt(), containerHeight.roundToInt()), layoutDirection!!
+            )
+            assertEquals(offset, bounds.topLeft.round())
+        }
+    }
+
+    @Test
+    fun testScaleToFitBottomCenterAlignment() {
+        var target by mutableStateOf(true)
+        var box1Coords: LayoutCoordinates? = null
+        var box2Coords: LayoutCoordinates? = null
+        var layoutDirection: LayoutDirection? = null
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                layoutDirection = LocalLayoutDirection.current
+                AnimatedContent(
+                    targetState = target,
+                    transitionSpec = {
+                        fadeIn() + scaleInToFitContainer(
+                            Alignment.BottomCenter
+                        ) togetherWith
+                            fadeOut(tween(100)) using
+                            SizeTransform { _, _ ->
+                                tween(100, easing = LinearEasing)
+                            }
+                    }) {
+                    if (target) {
+                        Box(
+                            Modifier
+                                .onPlaced {
+                                    box1Coords = it
+                                }
+                                .size(200.dp, 400.dp))
+                    } else {
+                        Box(
+                            Modifier
+                                .onPlaced { box2Coords = it }
+                                .size(100.dp, 50.dp))
+                    }
+                }
+            }
+        }
+
+        rule.waitForIdle()
+        rule.mainClock.autoAdvance = false
+        assertEquals(IntSize(200, 400), box1Coords?.size)
+        assertNull(box2Coords)
+
+        rule.runOnIdle {
+            // Start transition from true -> false, size 200,400 -> 100,50
+            target = false
+        }
+        rule.mainClock.advanceTimeByFrame()
+        repeat(10) {
+            rule.mainClock.advanceTimeByFrame()
+            val playTime = 16 * it
+            val bounds = box2Coords?.boundsInRoot()
+            assertNotNull(bounds)
+            val fraction = (playTime / 100f).coerceAtMost(1f)
+            val width = 200 * (1 - fraction) + 100 * fraction
+            val containerHeight = 400 * (1 - fraction) + 50 * fraction
+            // Since we are testing default behavior, the scaling is based on width.
+            val height = width / 100f * 50
+            assertEquals(width, bounds!!.width, 0.01f)
+            assertEquals(height, bounds.height, 0.01f)
+            val offset = Alignment.BottomCenter.align(
+                IntSize(width.roundToInt(), height.roundToInt()),
+                IntSize(width.roundToInt(), containerHeight.roundToInt()), layoutDirection!!
+            )
+            assertEquals(offset, bounds.topLeft.round())
+        }
+    }
+
+    @Test
+    fun testScaleToFitInsideBottomEndAlignment() {
+        var target by mutableStateOf(true)
+        var box1Coords: LayoutCoordinates? = null
+        var box2Coords: LayoutCoordinates? = null
+        var layoutDirection: LayoutDirection? = null
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                layoutDirection = LocalLayoutDirection.current
+                AnimatedContent(
+                    targetState = target,
+                    transitionSpec = {
+                        fadeIn() + scaleInToFitContainer(
+                            Alignment.BottomEnd, ContentScale.Inside
+                        ) togetherWith
+                            fadeOut(tween(100)) using
+                            SizeTransform { _, _ ->
+                                tween(100, easing = LinearEasing)
+                            }
+                    }) {
+                    if (target) {
+                        Box(
+                            Modifier
+                                .onPlaced {
+                                    box1Coords = it
+                                }
+                                .size(200.dp, 400.dp))
+                    } else {
+                        Box(
+                            Modifier
+                                .onPlaced { box2Coords = it }
+                                .size(100.dp, 50.dp))
+                    }
+                }
+            }
+        }
+
+        rule.waitForIdle()
+        rule.mainClock.autoAdvance = false
+        assertEquals(IntSize(200, 400), box1Coords?.size)
+        assertNull(box2Coords)
+
+        rule.runOnIdle {
+            // Start transition from true -> false, size 200,400 -> 100,50
+            target = false
+        }
+        rule.mainClock.advanceTimeByFrame()
+        repeat(10) {
+            rule.mainClock.advanceTimeByFrame()
+            val playTime = 16 * it
+            val bounds = box2Coords?.boundsInRoot()
+            assertNotNull(bounds)
+            val fraction = (playTime / 100f).coerceAtMost(1f)
+            val width = 100f
+            val containerWidth = 200 * (1 - fraction) + 100 * fraction
+            val containerHeight = 400 * (1 - fraction) + 50 * fraction
+            // Since we are testing default behavior, the scaling is based on width.
+            val height = 50f
+            assertEquals(width, bounds!!.width, 0.01f)
+            assertEquals(height, bounds.height, 0.01f)
+            val offset = Alignment.BottomEnd.align(
+                IntSize(width.roundToInt(), height.roundToInt()),
+                IntSize(containerWidth.roundToInt(), containerHeight.roundToInt()),
+                layoutDirection!!
+            )
+            assertEquals(offset, bounds.topLeft.round())
+        }
+    }
+
+    @Test
+    fun testScaleToFitWithFitHeight() {
+        var target by mutableStateOf(true)
+        var box1Coords: LayoutCoordinates? = null
+        var box2Coords: LayoutCoordinates? = null
+        var layoutDirection: LayoutDirection? = null
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                layoutDirection = LocalLayoutDirection.current
+                AnimatedContent(
+                    targetState = target,
+                    transitionSpec = {
+                        fadeIn() + scaleInToFitContainer(
+                            Alignment.Center, ContentScale.FillHeight
+                        ) togetherWith fadeOut(tween(100)) using
+                            SizeTransform { _, _ ->
+                                tween(100, easing = LinearEasing)
+                            }
+                    }) {
+                    if (target) {
+                        Box(
+                            Modifier
+                                .onPlaced {
+                                    box1Coords = it
+                                }
+                                .size(200.dp, 400.dp))
+                    } else {
+                        Box(
+                            Modifier
+                                .onPlaced { box2Coords = it }
+                                .size(100.dp, 250.dp))
+                    }
+                }
+            }
+        }
+
+        rule.waitForIdle()
+        rule.mainClock.autoAdvance = false
+        assertEquals(IntSize(200, 400), box1Coords?.size)
+        assertNull(box2Coords)
+
+        rule.runOnIdle {
+            // Start transition from true -> false, size 200,400 -> 100,250
+            target = false
+        }
+        rule.mainClock.advanceTimeByFrame()
+        repeat(10) {
+            rule.mainClock.advanceTimeByFrame()
+            val playTime = 16 * it
+            val bounds = box2Coords?.boundsInRoot()
+            assertNotNull(bounds)
+            val fraction = (playTime / 100f).coerceAtMost(1f)
+            val height = 400 * (1 - fraction) + 250 * fraction
+            val containerWidth = 200 * (1 - fraction) + 100 * fraction
+            // Since we are testing default behavior, the scaling is based on width.
+            val width = height / 250f * 100
+            assertEquals(width, bounds!!.width, 0.01f)
+            assertEquals(height, bounds.height, 0.01f)
+            val offset = Alignment.Center.align(
+                IntSize(width.roundToInt(), height.roundToInt()),
+                IntSize(containerWidth.roundToInt(), height.roundToInt()), layoutDirection!!
+            )
+            assertEquals(offset, bounds.topLeft.round())
+        }
+    }
+
     @OptIn(ExperimentalAnimationApi::class)
     @Test
     fun testExitHoldDefersUntilAllFinished() {
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
index 4449080..da44816 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-@file:OptIn(InternalAnimationApi::class)
+@file:OptIn(InternalAnimationApi::class, ExperimentalAnimationApi::class)
 
 package androidx.compose.animation
 
@@ -38,6 +37,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.State
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.key
@@ -45,14 +45,20 @@
 import androidx.compose.runtime.mutableStateListOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.SnapshotStateList
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.graphics.TransformOrigin
+import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.layout.IntrinsicMeasurable
 import androidx.compose.ui.layout.IntrinsicMeasureScope
 import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.LookaheadScope
 import androidx.compose.ui.layout.Measurable
 import androidx.compose.ui.layout.MeasurePolicy
 import androidx.compose.ui.layout.MeasureResult
@@ -60,14 +66,20 @@
 import androidx.compose.ui.layout.ParentDataModifier
 import androidx.compose.ui.layout.Placeable
 import androidx.compose.ui.layout.layout
+import androidx.compose.ui.node.LayoutModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.toSize
 import androidx.compose.ui.util.fastForEach
 import androidx.compose.ui.util.fastForEachIndexed
+import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineScope
 
 /**
  * [AnimatedContent] is a container that automatically animates its content when [targetState]
@@ -283,9 +295,7 @@
  * [AnimatedContentTransitionScope] provides functions that are convenient and only applicable in the
  * context of [AnimatedContent], such as [slideIntoContainer] and [slideOutOfContainer].
  */
-
 sealed interface AnimatedContentTransitionScope<S> : Transition.Segment<S> {
-
     /**
      * Customizes the [SizeTransform] of a given [ContentTransform]. For example:
      *
@@ -395,13 +405,67 @@
      * @sample androidx.compose.animation.samples.SlideIntoContainerSample
      */
     val ExitTransition.Companion.Hold: ExitTransition get() = Hold
+
+    /**
+     * This returns the [Alignment] specified on [AnimatedContent].
+     */
+    val contentAlignment: Alignment
+
+    /**
+     * [scaleInToFitContainer] defines an [EnterTransition] that scales the incoming content
+     * based on the (potentially animating) container (i.e. [AnimatedContent]) size. [contentScale]
+     * defines the scaling function. By default, the incoming content will be scaled based on its
+     * width (i.e. [ContentScale.FillWidth]), so that the content fills the container's width.
+     * [alignment] can be used to specify the alignment of the scaled content
+     * within the container of AnimatedContent.
+     *
+     * [scaleInToFitContainer] will measure the content using the final (i.e. lookahead)
+     * constraints, in order to obtain the final layout and apply scaling to that final layout
+     * while the container is resizing.
+     *
+     * @sample androidx.compose.animation.samples.ScaleInToFitContainerSample
+     */
+    @ExperimentalAnimationApi
+    fun scaleInToFitContainer(
+        alignment: Alignment = contentAlignment,
+        contentScale: ContentScale = ContentScale.FillWidth
+    ): EnterTransition
+
+    /**
+     * [scaleOutToFitContainer] defines an [ExitTransition] that scales the outgoing content
+     * based on the (potentially animating) container (i.e. [AnimatedContent]) size.
+     * [contentScale] defines the scaling function. By default, the outgoing content will be scaled
+     * using [ContentScale.FillWidth], so that it fits the container's width.
+     * [alignment] can be used to specify the alignment of the scaled content
+     * within the container of AnimatedContent.
+     *
+     * [scaleOutToFitContainer] will measure the content using the constraints cached
+     * at the beginning of the exit animation so that the content does not get re-laid out during
+     * the exit animation, and instead only scaling will be applied as the container resizes.
+     *
+     * **IMPORTANT**: [scaleOutToFitContainer] does NOT keep the exiting content from being
+     * disposed. Therefore it relies on other ExitTransitions such as [fadeOut] to define a
+     * timeframe for when should be active.
+     *
+     * @sample androidx.compose.animation.samples.ScaleInToFitContainerSample
+     */
+    @ExperimentalAnimationApi
+    fun scaleOutToFitContainer(
+        alignment: Alignment = contentAlignment,
+        contentScale: ContentScale = ContentScale.FillWidth,
+    ): ExitTransition
 }
 
-internal class AnimatedContentTransitionScopeImpl<S> internal constructor(
+internal class AnimatedContentRootScope<S> internal constructor(
     internal val transition: Transition<S>,
-    internal var contentAlignment: Alignment,
+    lookaheadScope: LookaheadScope,
+    internal val coroutineScope: CoroutineScope,
+    override var contentAlignment: Alignment,
     internal var layoutDirection: LayoutDirection
-) : AnimatedContentTransitionScope<S> {
+) : AnimatedContentTransitionScope<S>, LookaheadScope by lookaheadScope {
+    lateinit var rootCoords: LayoutCoordinates
+    lateinit var rootLookaheadCoords: LayoutCoordinates
+
     /**
      * Initial state of a Transition Segment. This is the state that transition starts from.
      */
@@ -484,7 +548,6 @@
             return this == Left || this == Start && layoutDirection == LayoutDirection.Ltr ||
                 this == End && layoutDirection == LayoutDirection.Rtl
         }
-
     private val AnimatedContentTransitionScope.SlideDirection.isRight: Boolean
         get() {
             return this == Right || this == Start && layoutDirection == LayoutDirection.Rtl ||
@@ -532,7 +595,6 @@
             }
 
             towards.isRight -> slideOutHorizontally(animationSpec) {
-
                 val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
                 targetOffset.invoke(
                     -calculateOffset(IntSize(it, it), targetSize).x + targetSize.width
@@ -540,7 +602,6 @@
             }
 
             towards == Up -> slideOutVertically(animationSpec) {
-
                 val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
                 targetOffset.invoke(-calculateOffset(IntSize(it, it), targetSize).y - it)
             }
@@ -556,15 +617,45 @@
         }
     }
 
+    @ExperimentalAnimationApi
+    override fun scaleInToFitContainer(
+        alignment: Alignment,
+        contentScale: ContentScale
+    ): EnterTransition = EnterTransition(
+        ScaleToFitTransitionKey, ScaleToFitInLookaheadElement(
+            this@AnimatedContentRootScope,
+            contentScale,
+            alignment
+        )
+    )
+
+    @ExperimentalAnimationApi
+    override fun scaleOutToFitContainer(
+        alignment: Alignment,
+        contentScale: ContentScale
+    ): ExitTransition = ExitTransition(
+        ScaleToFitTransitionKey,
+        ScaleToFitInLookaheadElement(
+            this@AnimatedContentRootScope,
+            contentScale,
+            alignment
+        )
+    )
+
     internal var measuredSize: IntSize by mutableStateOf(IntSize.Zero)
-    internal val targetSizeMap = mutableMapOf<S, State<IntSize>>()
+    internal val targetSizeMap = mutableMapOf<S, MutableState<IntSize>>()
     internal var animatedSize: State<IntSize>? = null
 
     // Current size of the container. If there's any size animation, the current size will be
     // read from the animation value, otherwise we'll use the current
-    private val currentSize: IntSize
+    internal val currentSize: IntSize
         get() = animatedSize?.value ?: measuredSize
 
+    internal val targetSize: IntSize
+        get() = requireNotNull(targetSizeMap[targetState]) {
+            "Error: Target size for AnimatedContent has not been set."
+        }.value
+
     @Suppress("ComposableModifierFactory", "ModifierFactoryExtensionFunction")
     @Composable
     internal fun createSizeAnimationModifier(
@@ -574,17 +665,20 @@
         val sizeTransform = rememberUpdatedState(contentTransform.sizeTransform)
         if (transition.currentState == transition.targetState) {
             shouldAnimateSize = false
-        } else {
-            // TODO: CurrentSize is only relevant to enter/exit transition, not so much for sizeAnim
-            if (sizeTransform.value != null) {
-                shouldAnimateSize = true
-            }
+        } else if (sizeTransform.value != null) {
+            shouldAnimateSize = true
         }
+
         return if (shouldAnimateSize) {
-            val sizeAnimation = transition.createDeferredAnimation(IntSize.VectorConverter)
+            val sizeAnimation =
+                transition.createDeferredAnimation(IntSize.VectorConverter, "sizeTransform")
             remember(sizeAnimation) {
                 (if (sizeTransform.value?.clip == false) Modifier else Modifier.clipToBounds())
-                    .then(SizeModifier(sizeAnimation, sizeTransform))
+                    .then(
+                        SizeModifierInLookaheadElement(
+                            this, sizeAnimation, sizeTransform
+                        )
+                    )
             }
         } else {
             animatedSize = null
@@ -594,42 +688,11 @@
 
     // This helps track the target measurable without affecting the placement order. Target
     // measurable needs to be measured first but placed last.
-    internal data class ChildData(var isTarget: Boolean) : ParentDataModifier {
+    internal data class ChildData<T>(var targetState: T) : ParentDataModifier {
         override fun Density.modifyParentData(parentData: Any?): Any {
             return this@ChildData
         }
     }
-
-    private inner class SizeModifier(
-        val sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
-        val sizeTransform: State<SizeTransform?>,
-    ) : LayoutModifierWithPassThroughIntrinsics() {
-
-        override fun MeasureScope.measure(
-            measurable: Measurable,
-            constraints: Constraints
-        ): MeasureResult {
-
-            val placeable = measurable.measure(constraints)
-            val size = sizeAnimation.animate(
-                transitionSpec = {
-                    val initial = targetSizeMap[initialState]?.value ?: IntSize.Zero
-                    val target = targetSizeMap[targetState]?.value ?: IntSize.Zero
-
-                    sizeTransform.value?.createAnimationSpec(initial, target) ?: spring()
-                }
-            ) {
-                targetSizeMap[it]?.value ?: IntSize.Zero
-            }
-            animatedSize = size
-            val offset = contentAlignment.align(
-                IntSize(placeable.width, placeable.height), size.value, LayoutDirection.Ltr
-            )
-            return layout(size.value.width, size.value.height) {
-                placeable.place(offset)
-            }
-        }
-    }
 }
 
 /**
@@ -706,153 +769,269 @@
     content: @Composable() AnimatedContentScope.(targetState: S) -> Unit
 ) {
     val layoutDirection = LocalLayoutDirection.current
-    val rootScope = remember(this) {
-        AnimatedContentTransitionScopeImpl(this, contentAlignment, layoutDirection)
-    }
+    val coroutineScope = rememberCoroutineScope()
+    LookaheadScope {
+        val rootScope = remember(this@AnimatedContent) {
+            AnimatedContentRootScope(
+                this@AnimatedContent, this@LookaheadScope,
+                coroutineScope, contentAlignment, layoutDirection
+            )
+        }
+        val currentlyVisible = remember(this) { mutableStateListOf(currentState) }
+        val contentMap = remember(this) { mutableMapOf<S, @Composable() () -> Unit>() }
+        val constraintsMap = remember { mutableMapOf<S, Constraints>() }
 
-    // TODO: remove screen as soon as they are animated out
-    val currentlyVisible = remember(this) { mutableStateListOf(currentState) }
-    val contentMap = remember(this) { mutableMapOf<S, @Composable() () -> Unit>() }
-
-    // This is needed for tooling because it could change currentState directly,
-    // as opposed to changing target only. When that happens we need to clear all the
-    // visible content and only display the content for the new current state and target state.
-    if (!currentlyVisible.contains(currentState)) {
-        currentlyVisible.clear()
-        currentlyVisible.add(currentState)
-    }
-
-    if (currentState == targetState) {
-        if (currentlyVisible.size != 1 || currentlyVisible[0] != currentState) {
+        // This is needed for tooling because it could change currentState directly,
+        // as opposed to changing target only. When that happens we need to clear all the
+        // visible content and only display the content for the new current state and target state.
+        if (!currentlyVisible.contains(currentState)) {
             currentlyVisible.clear()
             currentlyVisible.add(currentState)
         }
-        if (contentMap.size != 1 || contentMap.containsKey(currentState)) {
+
+        if (currentState == targetState) {
+            if (currentlyVisible.size != 1 || currentlyVisible[0] != currentState) {
+                currentlyVisible.clear()
+                currentlyVisible.add(currentState)
+            }
+            if (contentMap.size != 1 || contentMap.containsKey(currentState)) {
+                contentMap.clear()
+            }
+            val targetConstraints = constraintsMap[targetState]
+            constraintsMap.clear()
+            targetConstraints?.let { constraintsMap[targetState] = it }
+            // TODO: Do we want to support changing contentAlignment amid animation?
+            rootScope.contentAlignment = contentAlignment
+            rootScope.layoutDirection = layoutDirection
+        } else if (!currentlyVisible.contains(targetState)) {
+            // Currently visible list always keeps the targetState at the end of the list, unless
+            // it's already in the list in the case of interruption. This makes the composable
+            // associated with the targetState get placed last, so the target composable will be
+            // displayed on top of content associated with other states, unless zIndex is specified.
+            // Replace the target with the same key if any.
+            val id = currentlyVisible.indexOfFirst { contentKey(it) == contentKey(targetState) }
+            if (id == -1) {
+                currentlyVisible.add(targetState)
+            } else {
+                currentlyVisible[id] = targetState
+            }
+        }
+        if (!contentMap.containsKey(targetState) || !contentMap.containsKey(currentState)) {
             contentMap.clear()
-        }
-        // TODO: Do we want to support changing contentAlignment amid animation?
-        rootScope.contentAlignment = contentAlignment
-        rootScope.layoutDirection = layoutDirection
-    }
-
-    // Currently visible list always keeps the targetState at the end of the list, unless it's
-    // already in the list in the case of interruption. This makes the composable associated with
-    // the targetState get placed last, so the target composable will be displayed on top of
-    // content associated with other states, unless zIndex is specified.
-    if (currentState != targetState && !currentlyVisible.contains(targetState)) {
-        // Replace the target with the same key if any
-        val id = currentlyVisible.indexOfFirst { contentKey(it) == contentKey(targetState) }
-        if (id == -1) {
-            currentlyVisible.add(targetState)
-        } else {
-            currentlyVisible[id] = targetState
-        }
-    }
-
-    if (!contentMap.containsKey(targetState) || !contentMap.containsKey(currentState)) {
-        contentMap.clear()
-        currentlyVisible.fastForEach { stateForContent ->
-            contentMap[stateForContent] = {
-                val specOnEnter = remember { transitionSpec(rootScope) }
-                // NOTE: enter and exit for this AnimatedVisibility will be using different spec,
-                // naturally.
-                val exit =
-                    remember(segment.targetState == stateForContent) {
-                        if (segment.targetState == stateForContent) {
-                            ExitTransition.None
-                        } else {
-                            rootScope.transitionSpec().initialContentExit
-                        }
-                    }
-                val childData = remember {
-                    AnimatedContentTransitionScopeImpl.ChildData(stateForContent == targetState)
+            val enter = transitionSpec(rootScope).targetContentEnter
+            val exit = rootScope.transitionSpec().initialContentExit
+            val zIndex = transitionSpec(rootScope).targetContentZIndex
+            currentlyVisible.fastForEach { stateForContent ->
+                contentMap[stateForContent] = {
+                    PopulateContentFor(
+                        stateForContent, rootScope, enter, exit, zIndex, currentlyVisible, content
+                    )
                 }
-                // TODO: Will need a custom impl of this to: 1) get the signal for when
-                // the animation is finished, 2) get the target size properly
-                AnimatedEnterExitImpl(
-                    this,
-                    { it == stateForContent },
-                    enter = specOnEnter.targetContentEnter,
-                    exit = exit,
-                    modifier = Modifier
-                        .layout { measurable, constraints ->
-                            val placeable = measurable.measure(constraints)
-                            layout(placeable.width, placeable.height) {
-                                placeable.place(0, 0, zIndex = specOnEnter.targetContentZIndex)
+            }
+        }
+        val contentTransform = remember(rootScope, segment) { transitionSpec(rootScope) }
+        val sizeModifier = rootScope.createSizeAnimationModifier(contentTransform)
+        Layout(
+            modifier = modifier
+                .layout { measurable, constraints ->
+                    val placeable = measurable.measure(constraints)
+                    layout(placeable.width, placeable.height) {
+                        coordinates?.let {
+                            if (isLookingAhead) {
+                                rootScope.rootLookaheadCoords = it
+                            } else {
+                                rootScope.rootCoords = it
                             }
                         }
-                        .then(childData.apply { isTarget = stateForContent == targetState }),
-                    shouldDisposeBlock = { currentState, targetState ->
-                        currentState == EnterExitState.PostExit &&
-                            targetState == EnterExitState.PostExit &&
-                            !exit.data.hold
-                    }
-                ) {
-                    // TODO: Should Transition.AnimatedVisibility have an end listener?
-                    DisposableEffect(this) {
-                        onDispose {
-                            currentlyVisible.remove(stateForContent)
-                            rootScope.targetSizeMap.remove(stateForContent)
-                        }
-                    }
-                    rootScope.targetSizeMap[stateForContent] =
-                        (this as AnimatedVisibilityScopeImpl).targetSize
-                    with(remember { AnimatedContentScopeImpl(this) }) {
-                        content(stateForContent)
+                        placeable.place(0, 0)
                     }
                 }
+                .then(sizeModifier),
+            content = {
+                currentlyVisible.forEach {
+                    key(contentKey(it)) { contentMap[it]?.invoke() }
+                }
+            },
+            measurePolicy = remember {
+                AnimatedContentMeasurePolicy(
+                    rootScope, constraintsMap
+                )
             }
-        }
+        )
     }
-
-    val contentTransform = remember(rootScope, segment) { transitionSpec(rootScope) }
-    val sizeModifier = rootScope.createSizeAnimationModifier(contentTransform)
-    Layout(
-        modifier = modifier.then(sizeModifier),
-        content = {
-            currentlyVisible.forEach {
-                key(contentKey(it)) {
-                    contentMap[it]?.invoke()
-                }
-            }
-        },
-        measurePolicy = remember { AnimatedContentMeasurePolicy(rootScope) }
-    )
 }
 
-private class AnimatedContentMeasurePolicy(val rootScope: AnimatedContentTransitionScopeImpl<*>) :
-    MeasurePolicy {
+/**
+ * Creates content for a specific state based on the current Transition, enter/exit and the content
+ * lookup lambda.
+ */
+@Composable
+private inline fun <S> Transition<S>.PopulateContentFor(
+    stateForContent: S,
+    rootScope: AnimatedContentRootScope<S>,
+    enter: EnterTransition,
+    exit: ExitTransition,
+    zIndex: Float,
+    currentlyVisible: SnapshotStateList<S>,
+    crossinline content: @Composable() AnimatedContentScope.(targetState: S) -> Unit
+) {
+    var activeEnter by remember { mutableStateOf(enter) }
+    var activeExit by remember { mutableStateOf(ExitTransition.None) }
+    val targetZIndex = remember { zIndex }
+
+    val isEntering = targetState == stateForContent
+    if (targetState == currentState) {
+        // Transition finished, reset active enter & exit.
+        activeEnter = androidx.compose.animation.EnterTransition.None
+        activeExit = androidx.compose.animation.ExitTransition.None
+    } else if (isEntering) {
+        // If the previous enter transition never finishes when multiple
+        // interruptions happen, avoid adding new enter transitions for simplicity.
+        if (activeEnter == androidx.compose.animation.EnterTransition.None)
+            activeEnter += enter
+    } else {
+        // If the previous exit transition never finishes when multiple
+        // interruptions happen, avoid adding new enter transitions for simplicity.
+        if (activeExit == androidx.compose.animation.ExitTransition.None) {
+            activeExit += exit
+        }
+    }
+    val childData = remember { AnimatedContentRootScope.ChildData(stateForContent) }
+    AnimatedEnterExitImpl(
+        this,
+        { it == stateForContent },
+        enter = activeEnter,
+        exit = activeExit,
+        modifier = Modifier
+            .layout { measurable, constraints ->
+                val placeable = measurable.measure(constraints)
+                layout(placeable.width, placeable.height) {
+                    placeable.place(0, 0, zIndex = targetZIndex)
+                }
+            }
+            .then(childData)
+            .then(
+                if (isEntering) {
+                    activeEnter[ScaleToFitTransitionKey]
+                        ?: activeExit[ScaleToFitTransitionKey] ?: androidx.compose.ui.Modifier
+                } else {
+                    activeExit[ScaleToFitTransitionKey]
+                        ?: activeEnter[ScaleToFitTransitionKey] ?: androidx.compose.ui.Modifier
+                }
+            ),
+        shouldDisposeBlock = { currentState, targetState ->
+            currentState == androidx.compose.animation.EnterExitState.PostExit &&
+                targetState == androidx.compose.animation.EnterExitState.PostExit &&
+                !activeExit.data.hold
+        },
+        onLookaheadMeasured = {
+            if (isEntering) rootScope.targetSizeMap.getOrPut(targetState) {
+                mutableStateOf(it)
+            }.value = it
+        }
+    ) {
+        // TODO: Should Transition.AnimatedVisibility have an end listener?
+        DisposableEffect(this) {
+            onDispose {
+                currentlyVisible.remove(stateForContent)
+                rootScope.targetSizeMap.remove(stateForContent)
+            }
+        }
+        with(remember { AnimatedContentScopeImpl(this) }) {
+            content(stateForContent)
+        }
+    }
+}
+
+/**
+ * This measure policy returns the target content size in the lookahead pass, and the max width
+ * and height needed for all contents to fit during the main measure pass.
+ *
+ * The measure policy will measure all children with lookahead constraints. For outgoing content,
+ * we will use the constraints recorded before the content started to exit. This enables the
+ * outgoing content to not change constraints on its way out.
+ */
+@Suppress("UNCHECKED_CAST")
+private class AnimatedContentMeasurePolicy<S>(
+    val rootScope: AnimatedContentRootScope<S>,
+    val constraintsMap: MutableMap<S, Constraints>
+) : MeasurePolicy {
     override fun MeasureScope.measure(
         measurables: List<Measurable>,
         constraints: Constraints
     ): MeasureResult {
         val placeables = arrayOfNulls<Placeable>(measurables.size)
         // Measure the target composable first (but place it on top unless zIndex is specified)
+        val targetState = rootScope.targetState
         measurables.fastForEachIndexed { index, measurable ->
-            if ((measurable.parentData as? AnimatedContentTransitionScopeImpl.ChildData)
-                    ?.isTarget == true
+            if ((measurable.parentData as? AnimatedContentRootScope.ChildData<*>)
+                    ?.targetState == targetState
             ) {
-                placeables[index] = measurable.measure(constraints)
+                // Record lookahead constraints and always use it to measure target content.
+                val lookaheadConstraints = if (isLookingAhead) {
+                    constraintsMap[targetState] = constraints
+                    constraints
+                } else {
+                    requireNotNull(constraintsMap[targetState]) {
+                        "Lookahead pass was never done for target content."
+                    }
+                }
+                placeables[index] = measurable.measure(lookaheadConstraints)
             }
         }
+        // If no content is defined for target state, set the target size to zero
+        rootScope.targetSizeMap.getOrPut(targetState) { mutableStateOf(IntSize.Zero) }
+
+        val initialState = rootScope.initialState
         // Measure the non-target composables after target, since these have no impact on
         // container size in the size animation.
         measurables.fastForEachIndexed { index, measurable ->
+            val stateForContent =
+                (measurable.parentData as? AnimatedContentRootScope.ChildData<*>)
+                    ?.targetState
             if (placeables[index] == null) {
-                placeables[index] = measurable.measure(constraints)
+                val lookaheadConstraints =
+                    constraintsMap[stateForContent] ?: if (isLookingAhead) {
+                        constraintsMap[stateForContent as S] = constraints
+                        constraints
+                    } else {
+                        requireNotNull(constraintsMap[stateForContent as S]) {
+                            "Error: Lookahead pass never happened for state: $stateForContent"
+                        }
+                    }
+                placeables[index] = measurable.measure(lookaheadConstraints).also {
+                    // If the initial state size isn't in the map, add it. This could be possible
+                    // when the initial state is specified to be different than target state upon
+                    // entering composition.
+                    if (stateForContent == initialState &&
+                        isLookingAhead &&
+                        !rootScope.targetSizeMap.containsKey(initialState)
+                    ) {
+                        rootScope.targetSizeMap[initialState] =
+                            mutableStateOf(IntSize(it.width, it.height))
+                    }
+                }
             }
         }
-
-        val maxWidth: Int = placeables.maxByOrNull { it?.width ?: 0 }?.width ?: 0
-        val maxHeight = placeables.maxByOrNull { it?.height ?: 0 }?.height ?: 0
-        rootScope.measuredSize = IntSize(maxWidth, maxHeight)
+        val lookaheadSize = rootScope.targetSizeMap[targetState]!!.value
+        val measuredWidth = if (isLookingAhead) {
+            lookaheadSize.width
+        } else {
+            placeables.maxByOrNull { it?.width ?: 0 }?.width ?: 0
+        }
+        val measuredHeight = if (isLookingAhead) {
+            lookaheadSize.height
+        } else {
+            placeables.maxByOrNull { it?.height ?: 0 }?.height ?: 0
+        }
+        rootScope.measuredSize = IntSize(measuredWidth, measuredHeight)
         // Position the children.
-        return layout(maxWidth, maxHeight) {
+        return layout(measuredWidth, measuredHeight) {
             placeables.forEach { placeable ->
                 placeable?.let {
                     val offset = rootScope.contentAlignment.align(
                         IntSize(it.width, it.height),
-                        IntSize(maxWidth, maxHeight),
+                        IntSize(measuredWidth, measuredHeight),
                         LayoutDirection.Ltr
                     )
                     it.place(offset.x, offset.y)
@@ -881,3 +1060,154 @@
         width: Int
     ) = measurables.asSequence().map { it.maxIntrinsicHeight(width) }.maxOrNull() ?: 0
 }
+
+private class SizeModifierInLookaheadNode<S>(
+    var rootScope: AnimatedContentRootScope<S>,
+    var sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
+    var sizeTransform: State<SizeTransform?>,
+) : LayoutModifierNodeWithPassThroughIntrinsics() {
+
+    override fun MeasureScope.measure(
+        measurable: Measurable,
+        constraints: Constraints,
+    ): MeasureResult {
+        val placeable = measurable.measure(constraints)
+        val size = if (isLookingAhead) {
+            val targetSize = IntSize(placeable.width, placeable.height)
+            // lookahead pass
+            rootScope.animatedSize = sizeAnimation.animate(
+                transitionSpec = {
+                    val initial = rootScope.targetSizeMap[initialState]?.value ?: IntSize.Zero
+                    val target = rootScope.targetSizeMap[targetState]?.value ?: IntSize.Zero
+                    sizeTransform.value?.createAnimationSpec(initial, target) ?: spring()
+                }
+            ) {
+                rootScope.targetSizeMap[it]?.value ?: IntSize.Zero
+            }
+            targetSize
+        } else {
+            rootScope.animatedSize!!.value
+        }
+        val offset = rootScope.contentAlignment.align(
+            IntSize(placeable.width, placeable.height), size, LayoutDirection.Ltr
+        )
+        return layout(size.width, size.height) {
+            placeable.place(offset)
+        }
+    }
+}
+
+private data class SizeModifierInLookaheadElement<S>(
+    val rootScope: AnimatedContentRootScope<S>,
+    val sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
+    val sizeTransform: State<SizeTransform?>,
+) : ModifierNodeElement<SizeModifierInLookaheadNode<S>>() {
+    override fun create(): SizeModifierInLookaheadNode<S> {
+        return SizeModifierInLookaheadNode(rootScope, sizeAnimation, sizeTransform)
+    }
+
+    override fun update(node: SizeModifierInLookaheadNode<S>) {
+        node.rootScope = rootScope
+        node.sizeTransform = sizeTransform
+        node.sizeAnimation = sizeAnimation
+    }
+
+    override fun InspectorInfo.inspectableProperties() {
+        name = "sizeTransform"
+        properties["sizeTransform"] = sizeTransform
+        properties["sizeAnimation"] = sizeAnimation
+    }
+}
+
+private data class ScaleToFitInLookaheadElement(
+    val rootScope: AnimatedContentRootScope<*>,
+    val contentScale: ContentScale,
+    val alignment: Alignment
+) : ModifierNodeElement<ScaleToFitInLookaheadNode>() {
+    override fun create(): ScaleToFitInLookaheadNode =
+        ScaleToFitInLookaheadNode(rootScope, contentScale, alignment)
+
+    override fun update(node: ScaleToFitInLookaheadNode) {
+        node.rootScope = rootScope
+        node.contentScale = contentScale
+        node.alignment = alignment
+    }
+
+    override fun InspectorInfo.inspectableProperties() {
+        name = "scaleToFit"
+        properties["rootScope"] = rootScope
+        properties["scale"] = contentScale
+        properties["alignment"] = alignment
+    }
+}
+
+/**
+ * Creates a Modifier Node to: 1) measure the layout with lookahead constraints, 2) scale the
+ * resulting (potentially unfitting) layout based on the resizing container using the given
+ * [contentScale] lambda.
+ *
+ * This node is designed to work in a lookahead scope, therefore it anticipates lookahead pass
+ * before actual measure pass.
+ */
+private class ScaleToFitInLookaheadNode(
+    var rootScope: AnimatedContentRootScope<*>,
+    var contentScale: ContentScale,
+    var alignment: Alignment
+) : Modifier.Node(), LayoutModifierNode {
+    private var lookaheadConstraints: Constraints = Constraints()
+        set(value) {
+            lookaheadPassOccurred = true
+            field = value
+        }
+        get() {
+            require(lookaheadPassOccurred) {
+                "Error: Attempting to read lookahead constraints before lookahead pass."
+            }
+            return field
+        }
+    private var lookaheadPassOccurred = false
+
+    override fun onDetach() {
+        super.onDetach()
+        lookaheadPassOccurred = false
+    }
+
+    override fun MeasureScope.measure(
+        measurable: Measurable,
+        constraints: Constraints
+    ): MeasureResult {
+        if (isLookingAhead) lookaheadConstraints = constraints
+        // Measure with lookahead constraints.
+        val placeable = measurable.measure(lookaheadConstraints)
+        val contentSize = IntSize(placeable.width, placeable.height)
+        val sizeToReport = if (isLookingAhead) {
+            // report size of the target content, as that's what the content will be scaled to.
+            rootScope.targetSize
+        } else {
+            // report current animated size && scale based on that and full size
+            rootScope.currentSize
+        }
+        val resolvedScale =
+            contentScale.computeScaleFactor(contentSize.toSize(), sizeToReport.toSize())
+        return layout(sizeToReport.width, sizeToReport.height) {
+            val (x, y) = alignment.align(
+                IntSize(
+                    (contentSize.width * resolvedScale.scaleX).roundToInt(),
+                    (contentSize.height * resolvedScale.scaleY).roundToInt()
+                ),
+                sizeToReport,
+                layoutDirection
+            )
+            placeable.placeWithLayer(x, y) {
+                scaleX = resolvedScale.scaleX
+                scaleY = resolvedScale.scaleY
+                transformOrigin = TransformOrigin(0f, 0f)
+            }
+        }
+    }
+}
+
+/**
+ * Fixed key to read customization out of EnterTransition and ExitTransition.
+ */
+private val ScaleToFitTransitionKey = Any()
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
index 7e03d6f..367c85b 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
@@ -49,6 +49,7 @@
 import androidx.compose.ui.layout.MeasurePolicy
 import androidx.compose.ui.layout.MeasureResult
 import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.layout.layout
 import androidx.compose.ui.platform.debugInspectorInfo
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.IntSize
@@ -129,7 +130,7 @@
     content: @Composable() AnimatedVisibilityScope.() -> Unit
 ) {
     val transition = updateTransition(visible, label)
-    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+    AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
 }
 
 /**
@@ -204,7 +205,7 @@
     content: @Composable() AnimatedVisibilityScope.() -> Unit
 ) {
     val transition = updateTransition(visible, label)
-    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+    AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
 }
 
 /**
@@ -277,7 +278,7 @@
     content: @Composable AnimatedVisibilityScope.() -> Unit
 ) {
     val transition = updateTransition(visible, label)
-    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+    AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
 }
 
 /**
@@ -383,7 +384,7 @@
     content: @Composable() AnimatedVisibilityScope.() -> Unit
 ) {
     val transition = updateTransition(visibleState, label)
-    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+    AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
 }
 
 /**
@@ -458,7 +459,7 @@
     content: @Composable() AnimatedVisibilityScope.() -> Unit
 ) {
     val transition = updateTransition(visibleState, label)
-    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+    AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
 }
 
 /**
@@ -534,7 +535,7 @@
     content: @Composable() AnimatedVisibilityScope.() -> Unit
 ) {
     val transition = updateTransition(visibleState, label)
-    AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+    AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
 }
 
 /**
@@ -607,7 +608,7 @@
     enter: EnterTransition = fadeIn() + expandIn(),
     exit: ExitTransition = shrinkOut() + fadeOut(),
     content: @Composable() AnimatedVisibilityScope.() -> Unit
-) = AnimatedEnterExitImpl(this, visible, modifier, enter, exit, content = content)
+) = AnimatedVisibilityImpl(this, visible, modifier, enter, exit, content = content)
 
 /**
  * This is the scope for the content of [AnimatedVisibility]. In this scope, direct and
@@ -719,8 +720,51 @@
     content()
 }
 
-// RowScope and ColumnScope AnimatedEnterExit extensions and AnimatedEnterExit without a receiver
-// converge here.
+/**
+ * RowScope and ColumnScope AnimatedVisibility extensions and AnimatedVisibility without a receiver
+ * converge here.
+ * AnimatedVisibilityImpl sets up 2 things: 1) It adds a modifier to report 0 size in lookahead
+ * when animating out. 2) It sets up a criteria for when content should be disposed.
+ */
+@OptIn(ExperimentalAnimationApi::class)
+@Composable
+internal fun <T> AnimatedVisibilityImpl(
+    transition: Transition<T>,
+    visible: (T) -> Boolean,
+    modifier: Modifier,
+    enter: EnterTransition,
+    exit: ExitTransition,
+    content: @Composable() AnimatedVisibilityScope.() -> Unit
+) {
+    AnimatedEnterExitImpl(
+        transition = transition,
+        visible = visible,
+        modifier = modifier.layout { measurable, constraints ->
+            val placeable = measurable.measure(constraints)
+            val (w, h) =
+                if (isLookingAhead && !visible(transition.targetState)) {
+                    IntSize.Zero
+                } else {
+                    IntSize(placeable.width, placeable.height)
+                }
+            layout(w, h) {
+                placeable.place(0, 0)
+            }
+        },
+        enter = enter,
+        exit = exit,
+        shouldDisposeBlock = { current, target -> current == target && target == PostExit },
+        content = content
+    )
+}
+
+/**
+ * Observes lookahead size.
+ */
+internal fun interface OnLookaheadMeasured {
+    fun invoke(size: IntSize)
+}
+
 @OptIn(
     ExperimentalTransitionApi::class,
     InternalAnimationApi::class,
@@ -733,9 +777,8 @@
     modifier: Modifier,
     enter: EnterTransition,
     exit: ExitTransition,
-    shouldDisposeBlock: (EnterExitState, EnterExitState) -> Boolean = { current, target ->
-        current == target && target == PostExit
-    },
+    shouldDisposeBlock: (EnterExitState, EnterExitState) -> Boolean,
+    onLookaheadMeasured: OnLookaheadMeasured? = null,
     content: @Composable() AnimatedVisibilityScope.() -> Unit
 ) {
     if (visible(transition.targetState) || visible(transition.currentState) ||
@@ -771,7 +814,21 @@
             val scope = remember(transition) { AnimatedVisibilityScopeImpl(childTransition) }
             Layout(
                 content = { scope.content() },
-                modifier = modifier.then(childTransition.createModifier(enter, exit, "Built-in")),
+                modifier = modifier
+                    .then(childTransition.createModifier(enter, exit, "Built-in")
+                        .then(if (onLookaheadMeasured != null) {
+                            Modifier.layout { measurable, constraints ->
+                                measurable.measure(constraints).run {
+                                    if (isLookingAhead) {
+                                        onLookaheadMeasured.invoke(IntSize(width, height))
+                                    }
+                                    layout(width, height) {
+                                        place(0, 0)
+                                    }
+                                }
+                            }
+                        } else Modifier)
+                    ),
                 measurePolicy = remember { AnimatedEnterExitMeasurePolicy(scope) }
             )
         }
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
index e9d8ea9..f5a9d27 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
@@ -113,7 +113,8 @@
                 fade = data.fade ?: enter.data.fade,
                 slide = data.slide ?: enter.data.slide,
                 changeSize = data.changeSize ?: enter.data.changeSize,
-                scale = data.scale ?: enter.data.scale
+                scale = data.scale ?: enter.data.scale,
+                effectsMap = data.effectsMap + enter.data.effectsMap
             )
         )
     }
@@ -198,7 +199,8 @@
                 slide = data.slide ?: exit.data.slide,
                 changeSize = data.changeSize ?: exit.data.changeSize,
                 scale = data.scale ?: exit.data.scale,
-                hold = data.hold || exit.data.hold
+                hold = data.hold || exit.data.hold,
+                effectsMap = data.effectsMap + exit.data.effectsMap
             )
         )
     }
@@ -796,6 +798,18 @@
     val animationSpec: FiniteAnimationSpec<Float>
 )
 
+internal fun EnterTransition(
+    key: Any,
+    node: ModifierNodeElement<out Modifier.Node>
+): EnterTransition =
+    EnterTransitionImpl(TransitionData(effectsMap = mapOf(key to node)))
+
+internal fun ExitTransition(
+    key: Any,
+    node: ModifierNodeElement<out Modifier.Node>
+): ExitTransition =
+    ExitTransitionImpl(TransitionData(effectsMap = mapOf(key to node)))
+
 @Immutable
 private class EnterTransitionImpl(override val data: TransitionData) : EnterTransition()
 
@@ -822,9 +836,18 @@
     val slide: Slide? = null,
     val changeSize: ChangeSize? = null,
     val scale: Scale? = null,
-    val hold: Boolean = false
+    val hold: Boolean = false,
+    val effectsMap: Map<Any, ModifierNodeElement<out Modifier.Node>> = emptyMap()
 )
 
+@Suppress("ModifierFactoryExtensionFunction", "ModifierFactoryReturnType")
+internal operator fun EnterTransition.get(key: Any): ModifierNodeElement<out Modifier.Node>? =
+    data.effectsMap[key]
+
+@Suppress("ModifierFactoryExtensionFunction", "ModifierFactoryReturnType")
+internal operator fun ExitTransition.get(key: Any): ModifierNodeElement<out Modifier.Node>? =
+    data.effectsMap[key]
+
 @OptIn(ExperimentalAnimationApi::class, InternalAnimationApi::class)
 @Suppress("ModifierFactoryExtensionFunction", "ComposableModifierFactory")
 @Composable
@@ -833,7 +856,6 @@
     exit: ExitTransition,
     label: String
 ): Modifier {
-
     // Active enter & active exit reference the enter and exit transition that is currently being
     // used. It is important to preserve the active enter/exit that was previously used before
     // changing target state, such that if the previous enter/exit is interrupted, we still hold
@@ -879,7 +901,6 @@
         activeExit.data.changeSize?.clip == false) || !shouldAnimateSizeChange
 
     val graphicsLayerBlock = createGraphicsLayerBlock(activeEnter, activeExit, label)
-
     return Modifier
         .graphicsLayer(clip = !disableClip)
         .then(
@@ -1026,9 +1047,6 @@
             }
         }
 
-    private fun targetConstraints(default: Constraints) =
-        if (lookaheadConstraintsAvailable) lookaheadConstraints else default
-
     val sizeTransitionSpec: Transition.Segment<EnterExitState>.() -> FiniteAnimationSpec<IntSize> =
         {
             when {
@@ -1097,15 +1115,15 @@
             val measuredSize = IntSize(placeable.width, placeable.height)
             lookaheadSize = measuredSize
             lookaheadConstraints = constraints
-            val sizeToReport = if (transition.targetState == EnterExitState.Visible)
-                measuredSize
-            else
-                IntSize.Zero
-            return layout(sizeToReport.width, sizeToReport.height) {
+            return layout(measuredSize.width, measuredSize.height) {
                 placeable.place(0, 0)
             }
         } else {
-            val placeable = measurable.measure(targetConstraints(constraints))
+            // Measure the content based on the current constraints passed down from parent.
+            // AnimatedContent will measure outgoing children with a cached constraints to avoid
+            // re-layout the outgoing content. At the animateEnterExit() level, it's not best not
+            // to make assumptions, which is why we use constraints from parent.
+            val placeable = measurable.measure(constraints)
             val measuredSize = IntSize(placeable.width, placeable.height)
             val target = if (lookaheadSize.isValid) lookaheadSize else measuredSize
             val animSize = sizeAnimation?.animate(sizeTransitionSpec) { sizeByState(it, target) }
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
index f100c5d..e1af9da 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
@@ -4117,4 +4117,38 @@
             }
         """
     )
+
+    @Test
+    fun test_ComposableLambdaWithUnusedParameter() = verifyComposeIrTransform(
+        source = """
+            import androidx.compose.runtime.*
+
+            val layoutLambda = @Composable { _: Int ->
+                Layout()
+            }
+        """,
+        extra = """
+            import androidx.compose.runtime.*
+
+            @Composable inline fun Layout() {}
+        """,
+        expectedTransformed = """
+            val layoutLambda: Function3<Int, Composer, Int, Unit> = ComposableSingletons%TestKt.lambda-1
+            internal object ComposableSingletons%TestKt {
+              val lambda-1: Function3<Int, Composer, Int, Unit> = composableLambdaInstance(<>, false) { <unused var>: Int, %composer: Composer?, %changed: Int ->
+                if (%changed and 0b01010001 !== 0b00010000 || !%composer.skipping) {
+                  if (isTraceInProgress()) {
+                    traceEventStart(<>, %changed, -1, <>)
+                  }
+                  Layout(%composer, 0)
+                  if (isTraceInProgress()) {
+                    traceEventEnd()
+                  }
+                } else {
+                  %composer.skipToGroupEnd()
+                }
+              }
+            }
+        """
+    )
 }
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt
index 606cc70..98786eb 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt
@@ -387,4 +387,88 @@
             }
         """
     )
+
+    @Test
+    fun testComposableFunInterfaceWAnonymousParam() = verifyComposeIrTransform(
+        """
+            import androidx.compose.runtime.*
+
+            fun interface Consumer {
+                @Composable operator fun invoke(t: Int)
+            }
+
+            @Composable fun Test(int: Int) {
+                Example { _ ->
+                }
+            }
+
+            @Composable fun Example(consumer: Consumer) {
+            }
+        """,
+        """
+            interface Consumer {
+              @Composable
+              abstract fun invoke(t: Int, %composer: Composer?, %changed: Int)
+            }
+            @Composable
+            fun Test(int: Int, %composer: Composer?, %changed: Int) {
+              %composer = %composer.startRestartGroup(<>)
+              sourceInformation(%composer, "C(Test)<Exampl...>:Test.kt")
+              if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+                if (isTraceInProgress()) {
+                  traceEventStart(<>, %changed, -1, <>)
+                }
+                Example(class <no name provided> : Consumer {
+                  @Composable
+                  override fun invoke(<unused var>: Int, %composer: Composer?, %changed: Int) {
+                    %composer = %composer.startRestartGroup(<>)
+                    sourceInformation(%composer, "C(invoke):Test.kt")
+                    if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+                      if (isTraceInProgress()) {
+                        traceEventStart(<>, %changed, -1, <>)
+                      }
+                      Unit
+                      if (isTraceInProgress()) {
+                        traceEventEnd()
+                      }
+                    } else {
+                      %composer.skipToGroupEnd()
+                    }
+                    val tmp0_rcvr = <this>
+                    %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                      tmp0_rcvr.invoke(<unused var>, %composer, updateChangedFlags(%changed or 0b0001))
+                    }
+                  }
+                }
+                <no name provided>(), %composer, 0)
+                if (isTraceInProgress()) {
+                  traceEventEnd()
+                }
+              } else {
+                %composer.skipToGroupEnd()
+              }
+              %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                Test(int, %composer, updateChangedFlags(%changed or 0b0001))
+              }
+            }
+            @Composable
+            fun Example(consumer: Consumer, %composer: Composer?, %changed: Int) {
+              %composer = %composer.startRestartGroup(<>)
+              sourceInformation(%composer, "C(Example):Test.kt")
+              if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+                if (isTraceInProgress()) {
+                  traceEventStart(<>, %changed, -1, <>)
+                }
+                if (isTraceInProgress()) {
+                  traceEventEnd()
+                }
+              } else {
+                %composer.skipToGroupEnd()
+              }
+              %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+                Example(consumer, %composer, updateChangedFlags(%changed or 0b0001))
+              }
+            }
+        """
+    )
 }
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
index e334859..07c13e3 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
@@ -1689,12 +1689,20 @@
         )
 
         if (defaultParam == null) {
-            require(parameterCount == defaultIndex) // param count is 1-based, index is 0-based
+            // param count is 1-based, index is 0-based
+            require(parameterCount == defaultIndex) {
+                "Expected $defaultIndex params for ${function.fqNameWhenAvailable}, " +
+                    "found $parameterCount"
+            }
         } else {
+            val expectedParamCount = defaultIndex +
+                defaultParamCount(contextParameterCount + numRealValueParameters)
             require(
-                parameterCount == defaultIndex +
-                    defaultParamCount(contextParameterCount + numRealValueParameters)
-            )
+                parameterCount == expectedParamCount
+            ) {
+                "Expected $expectedParamCount params for ${function.fqNameWhenAvailable}, " +
+                    "found $parameterCount"
+            }
         }
 
         val lambda = irLambdaExpression(
@@ -3875,7 +3883,6 @@
                         paramName.startsWith(KtxNameConventions.CHANGED_PARAMETER.identifier) ->
                             changedParams += param
                         paramName.startsWith("\$context_receiver_") ||
-                        paramName.startsWith("\$anonymous\$parameter") ||
                         paramName.startsWith("\$name\$for\$destructuring") ||
                         paramName.startsWith("\$noName_") ||
                         paramName == "\$this" -> Unit
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
index 04c7f2c..841ab83a 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
@@ -1572,7 +1572,8 @@
         get() = when {
             // FIR generates both <iterator> and tmp0_for_iterator...
             origin == IrDeclarationOrigin.FOR_LOOP_ITERATOR -> "<iterator>"
-            !useFir && origin == IrDeclarationOrigin.UNDERSCORE_PARAMETER -> "<unused var>"
+            // $anonymous$parameter$x vs $unused$var$x
+            origin == IrDeclarationOrigin.UNDERSCORE_PARAMETER -> "<unused var>"
             !useFir && name.asString().endsWith("_elvis_lhs") -> "<elvis>"
             !useFir && name.asString() == "\$this\$null" -> "<this>"
             else -> name.asString()
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 5383dcd7..478059f 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -881,7 +881,8 @@
   }
 
   public final class LazyLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
+    method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(kotlin.jvm.functions.Function0<? extends androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider> itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
   }
 
   @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public sealed interface LazyLayoutMeasureScope extends androidx.compose.ui.layout.MeasureScope {
@@ -1380,7 +1381,9 @@
   }
 
   @androidx.compose.runtime.Immutable public final class KeyboardOptions {
+    ctor @Deprecated public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
     ctor public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
+    method @Deprecated public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
     method public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
     method public boolean getAutoCorrect();
     method public int getCapitalization();
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 2bdd519..a608e1e 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -883,7 +883,8 @@
   }
 
   public final class LazyLayoutKt {
-    method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
+    method @Deprecated @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
+    method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(kotlin.jvm.functions.Function0<? extends androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider> itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
   }
 
   @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public sealed interface LazyLayoutMeasureScope extends androidx.compose.ui.layout.MeasureScope {
@@ -1382,7 +1383,9 @@
   }
 
   @androidx.compose.runtime.Immutable public final class KeyboardOptions {
+    ctor @Deprecated public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
     ctor public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
+    method @Deprecated public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
     method public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
     method public boolean getAutoCorrect();
     method public int getCapitalization();
diff --git a/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyGridScrollingBenchmark.kt b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyGridScrollingBenchmark.kt
index 2e190b3..bda7bb1 100644
--- a/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyGridScrollingBenchmark.kt
+++ b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyGridScrollingBenchmark.kt
@@ -22,9 +22,11 @@
 import androidx.compose.foundation.background
 import androidx.compose.foundation.gestures.scrollBy
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.layout.requiredWidth
 import androidx.compose.foundation.lazy.grid.GridCells
 import androidx.compose.foundation.lazy.grid.LazyGridState
 import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
@@ -184,7 +186,7 @@
     LazyHorizontalGrid(
         rows = GridCells.Fixed(2),
         state = state,
-        modifier = Modifier.requiredHeight(400.dp).fillMaxWidth(),
+        modifier = Modifier.requiredWidth(400.dp).fillMaxHeight(),
         flingBehavior = NoFlingBehavior
     ) {
         items(2) {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/snapping/LazyGridSnapFlingBehaviorTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/snapping/LazyGridSnapFlingBehaviorTest.kt
index 6294141..b756f09 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/snapping/LazyGridSnapFlingBehaviorTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/snapping/LazyGridSnapFlingBehaviorTest.kt
@@ -61,6 +61,7 @@
 import kotlin.test.assertEquals
 import kotlin.test.assertNotEquals
 import kotlinx.coroutines.runBlocking
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -178,6 +179,7 @@
         }
     }
 
+    @Ignore // b/293513475
     @Test
     fun aboveThresholdVelocityBackward_notLargeEnoughScroll_shouldGoToPreviousPage() {
         var lazyGridState: LazyGridState? = null
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt
index d05d1f1..eab253b 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt
@@ -299,20 +299,19 @@
         indexToKey: (Int) -> Any = { getDefaultLazyLayoutKey(it) },
         content: @Composable (Int) -> Unit
     ) {
-        LazyLayout(
-            itemProvider = remember(itemCount, indexToKey, content as Any) {
-                object : LazyLayoutItemProvider {
-                    override val itemCount: Int = itemCount()
+        val provider = remember(itemCount, indexToKey, content as Any) {
+            object : LazyLayoutItemProvider {
+                override val itemCount: Int = itemCount()
 
-                    @Composable
-                    override fun Item(index: Int, key: Any) {
-                        content(index)
-                    }
-
-                    override fun getKey(index: Int) = indexToKey(index)
+                @Composable
+                override fun Item(index: Int, key: Any) {
+                    content(index)
                 }
+
+                override fun getKey(index: Int) = indexToKey(index)
             }
-        ) { constraints ->
+        }
+        LazyLayout(itemProvider = { provider }) { constraints ->
             val placeables = mutableListOf<Placeable>()
             repeat(itemCount()) { index ->
                 if (itemIsVisible(index)) {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutTest.kt
index 7cedc56..cd762bf 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutTest.kt
@@ -163,7 +163,7 @@
             LazyLayout(itemProvider) {
                 val constraints = Constraints.fixed(100, 100)
                 val items = mutableListOf<Placeable>()
-                repeat(itemProvider.itemCount) { index ->
+                repeat(itemProvider().itemCount) { index ->
                     items.addAll(measure(index, constraints))
                 }
                 layout(100, 100) {
@@ -204,7 +204,7 @@
             LazyLayout(itemProvider) {
                 val constraints = Constraints.fixed(100, 100)
                 val items = mutableListOf<Placeable>()
-                repeat(itemProvider.itemCount) { index ->
+                repeat(itemProvider().itemCount) { index ->
                     items.addAll(measure(index, constraints))
                 }
                 layout(100, 100) {
@@ -463,7 +463,7 @@
             override fun getKey(index: Int) = stateList[index]
         }
         rule.setContent {
-            LazyLayout(itemProvider) { constraint ->
+            LazyLayout({ itemProvider }) { constraint ->
                 measure(0, constraint)
                 layout(100, 100) {}
             }
@@ -483,8 +483,8 @@
     private fun itemProvider(
         itemCount: () -> Int,
         itemContent: @Composable (Int) -> Unit
-    ): LazyLayoutItemProvider {
-        return object : LazyLayoutItemProvider {
+    ): () -> LazyLayoutItemProvider {
+        val provider = object : LazyLayoutItemProvider {
             @Composable
             override fun Item(index: Int, key: Any) {
                 itemContent(index)
@@ -492,5 +492,6 @@
 
             override val itemCount: Int get() = itemCount()
         }
+        return { provider }
     }
 }
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/AndroidSelectionHandles.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/AndroidSelectionHandles.android.kt
index b4f0669..f9f10a3 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/AndroidSelectionHandles.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/AndroidSelectionHandles.android.kt
@@ -302,7 +302,7 @@
 /**
  * Computes whether the handle's appearance should be left-pointing or right-pointing.
  */
-private fun isLeft(
+internal fun isLeft(
     isStartHandle: Boolean,
     direction: ResolvedTextDirection,
     handlesCrossed: Boolean
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.android.kt
new file mode 100644
index 0000000..c6183a9
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.android.kt
@@ -0,0 +1,143 @@
+/*
+ * 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.compose.foundation.text2.selection
+
+import androidx.compose.foundation.text.Handle
+import androidx.compose.foundation.text.selection.DefaultSelectionHandle
+import androidx.compose.foundation.text.selection.HandleReferencePoint
+import androidx.compose.foundation.text.selection.SelectionHandleAnchor
+import androidx.compose.foundation.text.selection.SelectionHandleInfo
+import androidx.compose.foundation.text.selection.SelectionHandleInfoKey
+import androidx.compose.foundation.text.selection.isLeft
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.takeOrElse
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.style.ResolvedTextDirection
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntRect
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.round
+import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.PopupPositionProvider
+import androidx.compose.ui.window.PopupProperties
+
+@Composable
+internal actual fun TextFieldSelectionHandle2(
+    positionProvider: OffsetProvider,
+    isStartHandle: Boolean,
+    direction: ResolvedTextDirection,
+    handlesCrossed: Boolean,
+    modifier: Modifier
+) {
+    val isLeft = isLeft(isStartHandle, direction, handlesCrossed)
+    // The left selection handle's top right is placed at the given position, and vice versa.
+    val handleReferencePoint = if (isLeft) {
+        HandleReferencePoint.TopRight
+    } else {
+        HandleReferencePoint.TopLeft
+    }
+
+    HandlePopup2(
+        positionProvider = positionProvider,
+        handleReferencePoint = handleReferencePoint
+    ) {
+        DefaultSelectionHandle(
+            modifier = modifier
+                .semantics {
+                    this[SelectionHandleInfoKey] = SelectionHandleInfo(
+                        handle = if (isStartHandle) {
+                            Handle.SelectionStart
+                        } else {
+                            Handle.SelectionEnd
+                        },
+                        position = positionProvider.provide(),
+                        anchor = if (isLeft) {
+                            SelectionHandleAnchor.Left
+                        } else {
+                            SelectionHandleAnchor.Right
+                        }
+                    )
+                },
+            isStartHandle = isStartHandle,
+            direction = direction,
+            handlesCrossed = handlesCrossed
+        )
+    }
+}
+
+/**
+ * An alternative HandlePopup API that uses dynamic positioning. This enables us to update the
+ * handle position when onGloballyPositioned is called.
+ */
+@Composable
+internal fun HandlePopup2(
+    positionProvider: OffsetProvider,
+    handleReferencePoint: HandleReferencePoint,
+    content: @Composable () -> Unit
+) {
+    val popupPositioner = remember(handleReferencePoint) {
+        HandlePositionProvider2(handleReferencePoint, positionProvider)
+    }
+
+    Popup(
+        popupPositionProvider = popupPositioner,
+        properties = PopupProperties(
+            excludeFromSystemGesture = true,
+            clippingEnabled = false
+        ),
+        content = content
+    )
+}
+
+internal class HandlePositionProvider2(
+    private val handleReferencePoint: HandleReferencePoint,
+    private val positionProvider: OffsetProvider
+) : PopupPositionProvider {
+
+    override fun calculatePosition(
+        anchorBounds: IntRect,
+        windowSize: IntSize,
+        layoutDirection: LayoutDirection,
+        popupContentSize: IntSize
+    ): IntOffset {
+        val intOffset = positionProvider.provide().takeOrElse {
+            Offset(Float.MAX_VALUE, Float.MAX_VALUE)
+        }.round()
+
+        return when (handleReferencePoint) {
+            HandleReferencePoint.TopLeft ->
+                IntOffset(
+                    x = anchorBounds.left + intOffset.x,
+                    y = anchorBounds.top + intOffset.y
+                )
+            HandleReferencePoint.TopRight ->
+                IntOffset(
+                    x = anchorBounds.left + intOffset.x - popupContentSize.width,
+                    y = anchorBounds.top + intOffset.y
+                )
+            HandleReferencePoint.TopMiddle ->
+                IntOffset(
+                    x = anchorBounds.left + intOffset.x - popupContentSize.width / 2,
+                    y = anchorBounds.top + intOffset.y
+                )
+        }
+    }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayout.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayout.kt
index 3ad7f4f..6c08e89 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayout.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayout.kt
@@ -37,6 +37,12 @@
  * @param prefetchState allows to schedule items for prefetching
  * @param measurePolicy Measure policy which allows to only compose and measure needed items.
  */
+@Deprecated(
+    message = "Use an overload accepting a lambda prodicing an item provider instead",
+    replaceWith = ReplaceWith(
+        "LazyLayout({ itemProvider }, modifier, prefetchState, measurePolicy)"
+    )
+)
 @ExperimentalFoundationApi
 @Composable
 fun LazyLayout(
@@ -48,9 +54,19 @@
     LazyLayout({ itemProvider }, modifier, prefetchState, measurePolicy)
 }
 
+/**
+ * A layout that only composes and lays out currently needed items. Can be used to build
+ * efficient scrollable layouts.
+ *
+ * @param itemProvider lambda producing an item provider containing all the needed info about
+ * the items which could be used to compose and measure items as part of [measurePolicy].
+ * @param modifier to apply on the layout
+ * @param prefetchState allows to schedule items for prefetching
+ * @param measurePolicy Measure policy which allows to only compose and measure needed items.
+ */
 @ExperimentalFoundationApi
 @Composable
-internal fun LazyLayout(
+fun LazyLayout(
     itemProvider: () -> LazyLayoutItemProvider,
     modifier: Modifier = Modifier,
     prefetchState: LazyLayoutPrefetchState? = null,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
index 70a1d14..f7776ef 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
@@ -61,6 +61,23 @@
         val Default = KeyboardOptions()
     }
 
+    @Deprecated(
+        "Please use the new constructor that takes optional platformImeOptions parameter.",
+        level = DeprecationLevel.HIDDEN
+    )
+    constructor(
+        capitalization: KeyboardCapitalization = KeyboardCapitalization.None,
+        autoCorrect: Boolean = true,
+        keyboardType: KeyboardType = KeyboardType.Text,
+        imeAction: ImeAction = ImeAction.Default
+    ) : this(
+        capitalization = capitalization,
+        autoCorrect = autoCorrect,
+        keyboardType = keyboardType,
+        imeAction = imeAction,
+        platformImeOptions = null
+    )
+
     /**
      * Returns a new [ImeOptions] with the values that are in this [KeyboardOptions] and provided
      * params.
@@ -92,6 +109,25 @@
         )
     }
 
+    @Deprecated(
+        "Please use the new copy function that takes optional platformImeOptions parameter.",
+        level = DeprecationLevel.HIDDEN
+    )
+    fun copy(
+        capitalization: KeyboardCapitalization = this.capitalization,
+        autoCorrect: Boolean = this.autoCorrect,
+        keyboardType: KeyboardType = this.keyboardType,
+        imeAction: ImeAction = this.imeAction
+    ): KeyboardOptions {
+        return KeyboardOptions(
+            capitalization = capitalization,
+            autoCorrect = autoCorrect,
+            keyboardType = keyboardType,
+            imeAction = imeAction,
+            platformImeOptions = this.platformImeOptions
+        )
+    }
+
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is KeyboardOptions) return false
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
index 3e58a9e..a574637 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
@@ -32,7 +32,6 @@
 import androidx.compose.foundation.text.KeyboardActions
 import androidx.compose.foundation.text.KeyboardOptions
 import androidx.compose.foundation.text.heightInLines
-import androidx.compose.foundation.text.selection.SelectionHandle
 import androidx.compose.foundation.text.selection.SelectionHandleAnchor
 import androidx.compose.foundation.text.selection.SelectionHandleInfo
 import androidx.compose.foundation.text.selection.SelectionHandleInfoKey
@@ -47,6 +46,7 @@
 import androidx.compose.foundation.text2.input.internal.TextFieldDecoratorModifier
 import androidx.compose.foundation.text2.input.internal.TextFieldTextLayoutModifier
 import androidx.compose.foundation.text2.input.internal.TextLayoutState
+import androidx.compose.foundation.text2.selection.TextFieldSelectionHandle2
 import androidx.compose.foundation.text2.selection.TextFieldSelectionState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
@@ -302,29 +302,27 @@
 ) {
     val startHandleState = selectionState.startSelectionHandle
     if (startHandleState.visible) {
-        SelectionHandle(
-            position = startHandleState.position,
+        TextFieldSelectionHandle2(
+            positionProvider = { selectionState.startSelectionHandle.position },
             isStartHandle = true,
             direction = startHandleState.direction,
             handlesCrossed = startHandleState.handlesCrossed,
             modifier = Modifier.pointerInput(selectionState) {
                 with(selectionState) { selectionHandleGestures(true) }
-            },
-            content = null
+            }
         )
     }
 
     val endHandleState = selectionState.endSelectionHandle
     if (endHandleState.visible) {
-        SelectionHandle(
-            position = endHandleState.position,
+        TextFieldSelectionHandle2(
+            positionProvider = { selectionState.endSelectionHandle.position },
             isStartHandle = false,
             direction = endHandleState.direction,
             handlesCrossed = endHandleState.handlesCrossed,
             modifier = Modifier.pointerInput(selectionState) {
                 with(selectionState) { selectionHandleGestures(false) }
-            },
-            content = null
+            }
         )
     }
 }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.kt
new file mode 100644
index 0000000..1273aae
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.compose.foundation.text2.selection
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.text.style.ResolvedTextDirection
+
+@Composable
+internal expect fun TextFieldSelectionHandle2(
+    positionProvider: OffsetProvider,
+    isStartHandle: Boolean,
+    direction: ResolvedTextDirection,
+    handlesCrossed: Boolean,
+    modifier: Modifier
+)
+
+/**
+ * Avoids boxing of [Offset] which is an inline value class.
+ */
+internal fun interface OffsetProvider {
+    fun provide(): Offset
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionState.kt
index c12257d..9f4b7f1 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionState.kt
@@ -35,6 +35,7 @@
 import androidx.compose.foundation.text2.input.TextFieldState
 import androidx.compose.foundation.text2.input.getSelectedText
 import androidx.compose.foundation.text2.input.internal.TextLayoutState
+import androidx.compose.foundation.text2.input.internal.coerceIn
 import androidx.compose.foundation.text2.input.selectAll
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
@@ -726,7 +727,19 @@
         val directionOffset = if (isStartHandle) selection.start else max(selection.end - 1, 0)
         val direction = layoutResult.getBidiRunDirection(directionOffset)
         val handlesCrossed = selection.reversed
-        return TextFieldHandleState(true, position, direction, handlesCrossed)
+
+        // Handle normally is visible when it's out of bounds but when the handle is being dragged,
+        // we let it stay on the screen to maintain gesture continuation. However, we still want
+        // to coerce handle's position to visible bounds to not let it jitter while scrolling the
+        // TextField as the selection is expanding.
+        val coercedPosition = innerCoordinates?.visibleBounds()?.let { position.coerceIn(it) }
+            ?: position
+        return TextFieldHandleState(
+            visible = true,
+            position = coercedPosition,
+            direction = direction,
+            handlesCrossed = handlesCrossed
+        )
     }
 
     private fun getHandlePosition(isStartHandle: Boolean): Offset {
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.desktop.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.desktop.kt
new file mode 100644
index 0000000..8ac7119
--- /dev/null
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.desktop.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.compose.foundation.text2.selection
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.ResolvedTextDirection
+
+/**
+ * Handles are not supported on Desktop.
+ */
+@Composable
+internal actual fun TextFieldSelectionHandle2(
+    positionProvider: OffsetProvider,
+    isStartHandle: Boolean,
+    direction: ResolvedTextDirection,
+    handlesCrossed: Boolean,
+    modifier: Modifier
+) {}
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialPerfettoSdkBenchmark.kt
similarity index 97%
rename from compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialPerfettoSdkBenchmark.kt
index 3115e6b..002886f 100644
--- a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialPerfettoSdkBenchmark.kt
@@ -41,7 +41,7 @@
  */
 @OptIn(ExperimentalMetricApi::class)
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R) // TODO(234351579): Support API < 30
-class TrivialTracingBenchmark(private val composableName: String) {
+class TrivialPerfettoSdkBenchmark(private val composableName: String) {
     @get:Rule
     val benchmarkRule = MacrobenchmarkRule()
 
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupTracingBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt
similarity index 84%
rename from compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupTracingBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt
index 47cbb44..f9ca454 100644
--- a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupTracingBenchmark.kt
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt
@@ -26,7 +26,6 @@
 import androidx.testutils.measureStartup
 import org.hamcrest.CoreMatchers.`is`
 import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -35,7 +34,7 @@
 @OptIn(ExperimentalMetricApi::class)
 @LargeTest
 @RunWith(Parameterized::class)
-class TrivialStartupTracingBenchmark(
+class TrivialStartupPerfettoSdkBenchmark(
     private val startupMode: StartupMode,
     private val compilationMode: CompilationMode,
     private val isFullTracingEnabled: Boolean
@@ -43,8 +42,6 @@
     @get:Rule
     val benchmarkRule = MacrobenchmarkRule()
 
-    // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
-    @Ignore
     @Test
     fun startup() = try {
         Arguments.fullTracingEnableOverride = isFullTracingEnabled
@@ -52,9 +49,8 @@
 
         try {
             val perfettoSdkTraceSection = TraceSectionMetric(
-                "androidx.compose.integration.macrobenchmark.target." +
-                    "TrivialStartupTracingActivity.onCreate.<anonymous>" +
-                    " (TrivialStartupTracingActivity.kt:33)"
+                "%TrivialStartupTracingActivity.onCreate%" +
+                    " (TrivialStartupTracingActivity.kt:%)"
             )
             benchmarkRule.measureStartup(
                 compilationMode = compilationMode,
@@ -70,8 +66,11 @@
             if (!isFullTracingEnabled &&
                 e.message?.contains("Unable to read any metrics during benchmark") == true
             ) {
-                // this is expected, we don't expect Perfetto SDK Tracing section present
-                // when full tracing is disabled
+                // We are relying on the fact that Macrobenchmark will throw an exception when it
+                // cannot find any metrics, and given we are looking for one specific metric
+                // (a Composable function emitted by Compose Tracing), we are able to tell if
+                // Compose Tracing is working (enabled) or not, both of which we want to verify in
+                // this test.
             } else throw e // this is a legitimate failure
         }
     } finally {
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkOverheadBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkOverheadBenchmark.kt
new file mode 100644
index 0000000..0e22752
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkOverheadBenchmark.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.compose.integration.macrobenchmark
+
+import androidx.benchmark.Arguments
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.StartupMode
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.filters.LargeTest
+import androidx.testutils.createStartupCompilationParams
+import androidx.testutils.measureStartup
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+class TrivialStartupPerfettoSdkOverheadBenchmark(
+    private val startupMode: StartupMode,
+    private val compilationMode: CompilationMode,
+    private val isFullTracingEnabled: Boolean
+) {
+    @get:Rule
+    val benchmarkRule = MacrobenchmarkRule()
+
+    @Test
+    fun startup() = try {
+        Arguments.fullTracingEnableOverride = isFullTracingEnabled
+        assertThat(Arguments.fullTracingEnable, `is`(isFullTracingEnabled))
+
+        benchmarkRule.measureStartup(
+            compilationMode = compilationMode,
+            startupMode = startupMode,
+            packageName = "androidx.compose.integration.macrobenchmark.target"
+        ) {
+            action = "androidx.compose.integration.macrobenchmark.target." +
+                "TRIVIAL_STARTUP_TRACING_ACTIVITY"
+        }
+    } finally {
+        Arguments.fullTracingEnableOverride = null
+    }
+
+    companion object {
+        // intended for local testing of all possible configurations
+        private const val exhaustiveMode = false
+
+        @Parameterized.Parameters(name = "startup={0},compilation={1},fullTracing={2}")
+        @JvmStatic
+        fun parameters() =
+            when {
+                exhaustiveMode ->
+                    // complete set for testing locally
+                    createStartupCompilationParams()
+                        .flatMap { listOf(it + true, it + false) } /* full tracing enabled */
+                else ->
+                    // subset for testing in CI:
+                    // compilation isn't expected to affect this, so we just look at startup time
+                    // for cold and not, since the behavior is very different in those scenarios
+                    createStartupCompilationParams(
+                        listOf(StartupMode.COLD, StartupMode.WARM),
+                        listOf(CompilationMode.DEFAULT)
+                    ).map { it + true } /* full tracing enabled */
+            }
+    }
+}
diff --git a/compose/material3/material3-adaptive/api/current.txt b/compose/material3/material3-adaptive/api/current.txt
index bf5b32a..af140b8 100644
--- a/compose/material3/material3-adaptive/api/current.txt
+++ b/compose/material3/material3-adaptive/api/current.txt
@@ -96,6 +96,77 @@
     property public abstract androidx.compose.material3.adaptive.ThreePaneScaffoldValue layoutValue;
   }
 
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum NavigationSuiteAlignment {
+    method public static androidx.compose.material3.adaptive.NavigationSuiteAlignment valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.adaptive.NavigationSuiteAlignment[] values();
+    enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment BottomHorizontal;
+    enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment EndVertical;
+    enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment StartVertical;
+    enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment TopHorizontal;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteColors {
+    method public long getNavigationBarContainerColor();
+    method public long getNavigationBarContentColor();
+    method public long getNavigationDrawerContainerColor();
+    method public long getNavigationDrawerContentColor();
+    method public long getNavigationRailContainerColor();
+    method public long getNavigationRailContentColor();
+    property public final long navigationBarContainerColor;
+    property public final long navigationBarContentColor;
+    property public final long navigationDrawerContainerColor;
+    property public final long navigationDrawerContentColor;
+    property public final long navigationRailContainerColor;
+    property public final long navigationRailContentColor;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteDefaults {
+    method public String calculateFromAdaptiveInfo(androidx.compose.material3.adaptive.WindowAdaptiveInfo adaptiveInfo);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.adaptive.NavigationSuiteColors colors(optional long navigationBarContainerColor, optional long navigationBarContentColor, optional long navigationRailContainerColor, optional long navigationRailContentColor, optional long navigationDrawerContainerColor, optional long navigationDrawerContentColor);
+    method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationBarAlignment();
+    method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationDrawerAlignment();
+    method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationRailAlignment();
+    property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationBarAlignment;
+    property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationDrawerAlignment;
+    property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationRailAlignment;
+    field public static final androidx.compose.material3.adaptive.NavigationSuiteDefaults INSTANCE;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteItemColors {
+    method public androidx.compose.material3.NavigationBarItemColors getNavigationBarItemColors();
+    method public androidx.compose.material3.NavigationDrawerItemColors getNavigationDrawerItemColors();
+    method public androidx.compose.material3.NavigationRailItemColors getNavigationRailItemColors();
+    property public final androidx.compose.material3.NavigationBarItemColors navigationBarItemColors;
+    property public final androidx.compose.material3.NavigationDrawerItemColors navigationDrawerItemColors;
+    property public final androidx.compose.material3.NavigationRailItemColors navigationRailItemColors;
+  }
+
+  public final class NavigationSuiteScaffoldKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigationSuite(androidx.compose.material3.adaptive.NavigationSuiteScaffoldScope, optional androidx.compose.ui.Modifier modifier, optional String layoutType, optional androidx.compose.material3.adaptive.NavigationSuiteColors colors, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.NavigationSuiteScope,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigationSuiteScaffold(kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.NavigationSuiteScaffoldScope,kotlin.Unit> navigationSuite, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface NavigationSuiteScaffoldScope {
+    method public androidx.compose.ui.Modifier alignment(androidx.compose.ui.Modifier, androidx.compose.material3.adaptive.NavigationSuiteAlignment alignment);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface NavigationSuiteScope {
+    method public void item(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? badge, optional androidx.compose.material3.adaptive.NavigationSuiteItemColors? colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class NavigationSuiteType {
+    field public static final androidx.compose.material3.adaptive.NavigationSuiteType.Companion Companion;
+  }
+
+  public static final class NavigationSuiteType.Companion {
+    method public String getNavigationBar();
+    method public String getNavigationDrawer();
+    method public String getNavigationRail();
+    property public final String NavigationBar;
+    property public final String NavigationDrawer;
+    property public final String NavigationRail;
+  }
+
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class PaneAdaptedValue {
     field public static final androidx.compose.material3.adaptive.PaneAdaptedValue.Companion Companion;
   }
diff --git a/compose/material3/material3-adaptive/api/restricted_current.txt b/compose/material3/material3-adaptive/api/restricted_current.txt
index bf5b32a..af140b8 100644
--- a/compose/material3/material3-adaptive/api/restricted_current.txt
+++ b/compose/material3/material3-adaptive/api/restricted_current.txt
@@ -96,6 +96,77 @@
     property public abstract androidx.compose.material3.adaptive.ThreePaneScaffoldValue layoutValue;
   }
 
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum NavigationSuiteAlignment {
+    method public static androidx.compose.material3.adaptive.NavigationSuiteAlignment valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.adaptive.NavigationSuiteAlignment[] values();
+    enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment BottomHorizontal;
+    enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment EndVertical;
+    enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment StartVertical;
+    enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment TopHorizontal;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteColors {
+    method public long getNavigationBarContainerColor();
+    method public long getNavigationBarContentColor();
+    method public long getNavigationDrawerContainerColor();
+    method public long getNavigationDrawerContentColor();
+    method public long getNavigationRailContainerColor();
+    method public long getNavigationRailContentColor();
+    property public final long navigationBarContainerColor;
+    property public final long navigationBarContentColor;
+    property public final long navigationDrawerContainerColor;
+    property public final long navigationDrawerContentColor;
+    property public final long navigationRailContainerColor;
+    property public final long navigationRailContentColor;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteDefaults {
+    method public String calculateFromAdaptiveInfo(androidx.compose.material3.adaptive.WindowAdaptiveInfo adaptiveInfo);
+    method @androidx.compose.runtime.Composable public androidx.compose.material3.adaptive.NavigationSuiteColors colors(optional long navigationBarContainerColor, optional long navigationBarContentColor, optional long navigationRailContainerColor, optional long navigationRailContentColor, optional long navigationDrawerContainerColor, optional long navigationDrawerContentColor);
+    method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationBarAlignment();
+    method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationDrawerAlignment();
+    method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationRailAlignment();
+    property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationBarAlignment;
+    property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationDrawerAlignment;
+    property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationRailAlignment;
+    field public static final androidx.compose.material3.adaptive.NavigationSuiteDefaults INSTANCE;
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteItemColors {
+    method public androidx.compose.material3.NavigationBarItemColors getNavigationBarItemColors();
+    method public androidx.compose.material3.NavigationDrawerItemColors getNavigationDrawerItemColors();
+    method public androidx.compose.material3.NavigationRailItemColors getNavigationRailItemColors();
+    property public final androidx.compose.material3.NavigationBarItemColors navigationBarItemColors;
+    property public final androidx.compose.material3.NavigationDrawerItemColors navigationDrawerItemColors;
+    property public final androidx.compose.material3.NavigationRailItemColors navigationRailItemColors;
+  }
+
+  public final class NavigationSuiteScaffoldKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigationSuite(androidx.compose.material3.adaptive.NavigationSuiteScaffoldScope, optional androidx.compose.ui.Modifier modifier, optional String layoutType, optional androidx.compose.material3.adaptive.NavigationSuiteColors colors, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.NavigationSuiteScope,kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigationSuiteScaffold(kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.NavigationSuiteScaffoldScope,kotlin.Unit> navigationSuite, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface NavigationSuiteScaffoldScope {
+    method public androidx.compose.ui.Modifier alignment(androidx.compose.ui.Modifier, androidx.compose.material3.adaptive.NavigationSuiteAlignment alignment);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface NavigationSuiteScope {
+    method public void item(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? badge, optional androidx.compose.material3.adaptive.NavigationSuiteItemColors? colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+  }
+
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class NavigationSuiteType {
+    field public static final androidx.compose.material3.adaptive.NavigationSuiteType.Companion Companion;
+  }
+
+  public static final class NavigationSuiteType.Companion {
+    method public String getNavigationBar();
+    method public String getNavigationDrawer();
+    method public String getNavigationRail();
+    property public final String NavigationBar;
+    property public final String NavigationDrawer;
+    property public final String NavigationRail;
+  }
+
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class PaneAdaptedValue {
     field public static final androidx.compose.material3.adaptive.PaneAdaptedValue.Companion Companion;
   }
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.kt
index 956eb20..9620e34 100644
--- a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.kt
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.kt
@@ -65,22 +65,20 @@
  * The Navigation Suite Scaffold wraps the provided content and places the adequate provided
  * navigation component on the screen according to the current [NavigationSuiteType].
  *
- * @param modifier the [Modifier] to be applied to the navigation suite scaffold
  * @param navigationSuite the navigation component to be displayed, typically [NavigationSuite]
+ * @param modifier the [Modifier] to be applied to the navigation suite scaffold
  * @param containerColor the color used for the background of the navigation suite scaffold. Use
  * [Color.Transparent] to have no color
  * @param contentColor the preferred color for content inside the navigation suite scaffold.
  * Defaults to either the matching content color for [containerColor], or to the current
  * [LocalContentColor] if [containerColor] is not a color from the theme
  * @param content the content of your screen
- *
- * TODO: Remove "internal".
  */
 @ExperimentalMaterial3AdaptiveApi
 @Composable
-internal fun NavigationSuiteScaffold(
-    modifier: Modifier = Modifier,
+fun NavigationSuiteScaffold(
     navigationSuite: @Composable NavigationSuiteScaffoldScope.() -> Unit,
+    modifier: Modifier = Modifier,
     containerColor: Color = MaterialTheme.colorScheme.background,
     contentColor: Color = contentColorFor(containerColor),
     content: @Composable () -> Unit = {},
@@ -201,17 +199,15 @@
  * @param modifier the [Modifier] to be applied to the navigation component
  * @param layoutType the current [NavigationSuiteType] of the [NavigationSuiteScaffold]. Defaults to
  * [NavigationSuiteDefaults.calculateFromAdaptiveInfo]
- * @params colors [NavigationSuiteColors] that will be used to determine the container (background)
+ * @param colors [NavigationSuiteColors] that will be used to determine the container (background)
  * color of the navigation component and the preferred color for content inside the navigation
  * component
  * @param content the content inside the current navigation component, typically
  * [NavigationSuiteScope.item]s
- *
- * TODO: Remove "internal".
  */
 @ExperimentalMaterial3AdaptiveApi
 @Composable
-internal fun NavigationSuiteScaffoldScope.NavigationSuite(
+fun NavigationSuiteScaffoldScope.NavigationSuite(
     modifier: Modifier = Modifier,
     layoutType: NavigationSuiteType =
         NavigationSuiteDefaults.calculateFromAdaptiveInfo(WindowAdaptiveInfoDefault),
@@ -291,13 +287,9 @@
     }
 }
 
-/**
- * The scope associated with the [NavigationSuiteScaffold].
- *
- * TODO: Remove "internal".
- */
+/** The scope associated with the [NavigationSuiteScaffold]. */
 @ExperimentalMaterial3AdaptiveApi
-internal interface NavigationSuiteScaffoldScope {
+interface NavigationSuiteScaffoldScope {
     /**
      * [Modifier] that should be applied to the [NavigationSuite] of the [NavigationSuiteScaffold]
      * in order to determine its alignment on the screen.
@@ -312,11 +304,9 @@
  *
  * The alignment informs the Navigation Suite Scaffold how to properly place the expected navigation
  * component on the screen in relation to the Navigation Suite Scaffold's content.
- *
- * TODO: Remove "internal".
  */
 @ExperimentalMaterial3AdaptiveApi
-internal enum class NavigationSuiteAlignment {
+enum class NavigationSuiteAlignment {
     /** The navigation component is vertical and positioned at the start of the screen. */
     StartVertical,
     /** The navigation component is vertical and positioned at the end of the screen. */
@@ -327,13 +317,9 @@
     BottomHorizontal
 }
 
-/**
- * The scope associated with the [NavigationSuite].
- *
- * TODO: Remove "internal".
- */
+/** The scope associated with the [NavigationSuite]. */
 @ExperimentalMaterial3AdaptiveApi
-internal interface NavigationSuiteScope {
+interface NavigationSuiteScope {
 
     /**
      * This function sets the parameters of the default Material navigation item to be used with the
@@ -377,16 +363,11 @@
 /**
  * Class that describes the different navigation suite types of the [NavigationSuiteScaffold].
  *
- * The [NavigationSuiteType] informs the [NavigationSuite] of what navigation component to
- * expect.
- *
- * @param description the description of the [NavigationSuiteType]
- *
- * TODO: remove "internal"
+ * The [NavigationSuiteType] informs the [NavigationSuite] of what navigation component to expect.
  */
 @JvmInline
 @ExperimentalMaterial3AdaptiveApi
-internal value class NavigationSuiteType private constructor(private val description: String) {
+value class NavigationSuiteType private constructor(private val description: String) {
     override fun toString(): String {
         return description
     }
@@ -417,13 +398,9 @@
     }
 }
 
-/**
- * Contains the default values used by the [NavigationSuite].
- *
- * TODO: Remove "internal".
- */
+/** Contains the default values used by the [NavigationSuite]. */
 @ExperimentalMaterial3AdaptiveApi
-internal object NavigationSuiteDefaults {
+object NavigationSuiteDefaults {
     /**
      * Returns the expected [NavigationSuiteType] according to the provided [WindowAdaptiveInfo].
      * Usually used with the [NavigationSuite].
@@ -506,11 +483,9 @@
  * [NavigationSuite]
  * @param navigationDrawerContentColor the content color for the [PermanentDrawerSheet] of the
  * [NavigationSuite]
- *
- * TODO: Remove "internal".
  */
 @ExperimentalMaterial3AdaptiveApi
-internal class NavigationSuiteColors
+class NavigationSuiteColors
 internal constructor(
     val navigationBarContainerColor: Color,
     val navigationBarContentColor: Color,
@@ -532,11 +507,9 @@
  * [NavigationRailItem] of the [NavigationSuiteScope.item]
  * @param navigationDrawerItemColors the [NavigationDrawerItemColors] associated with the
  * [NavigationDrawerItem] of the [NavigationSuiteScope.item]
- *
- * TODO: Remove "internal".
  */
 @ExperimentalMaterial3AdaptiveApi
-internal class NavigationSuiteItemColors
+class NavigationSuiteItemColors
 internal constructor(
     val navigationBarItemColors: NavigationBarItemColors,
     val navigationRailItemColors: NavigationRailItemColors,
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index 31650af..fc64f3a 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -2006,18 +2006,14 @@
         if (inserting) {
             providers = parentScope.putValue(local, state)
             invalid = false
+            writerHasAProvider = true
         } else {
             val oldScope = reader.groupAux(reader.currentGroup) as PersistentCompositionLocalMap
             providers =
                 if ((!skipping || change) && (value.canOverride || !parentScope.contains(local)))
                     parentScope.putValue(local, state)
                 else oldScope
-            if (oldScope !== providers) {
-                invalid = true
-                writerHasAProvider = true
-            } else {
-                invalid = false
-            }
+            invalid = reusing || oldScope !== providers
         }
         if (invalid && !inserting) {
             providerUpdates[reader.currentGroup] = providers
@@ -3333,6 +3329,7 @@
     private fun reportFreeMovableContent(groupBeingRemoved: Int) {
 
         fun reportGroup(group: Int, needsNodeDelete: Boolean, nodeIndex: Int): Int {
+            val reader = reader
             return if (reader.hasMark(group)) {
                 // If the group has a mark then it is either a movable content group or a
                 // composition context group
@@ -3390,7 +3387,7 @@
                         }
                     }
                     reader.nodeCount(group)
-                } else reader.nodeCount(group)
+                } else if (reader.isNode(group)) 1 else reader.nodeCount(group)
             } else if (reader.containsMark(group)) {
                 // Traverse the group freeing the child movable content. This group is known to
                 // have at least one child that contains movable content because the group is
@@ -3423,8 +3420,8 @@
                     }
                     current += reader.groupSize(current)
                 }
-                runningNodeCount
-            } else reader.nodeCount(group)
+                if (reader.isNode(group)) 1 else runningNodeCount
+            } else if (reader.isNode(group)) 1 else reader.nodeCount(group)
         }
         reportGroup(groupBeingRemoved, needsNodeDelete = false, nodeIndex = 0)
         changeListWriter.endNodeMovement()
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
index cde9d7c..1073e39 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
@@ -244,10 +244,9 @@
 @Composable
 @OptIn(InternalComposeApi::class)
 fun CompositionLocalProvider(value: ProvidedValue<*>, content: @Composable () -> Unit) {
-    // TODO(b/292224893): Switch this to the higher-performance startProvider()
-    currentComposer.startProviders(arrayOf(value))
+    currentComposer.startProvider(value)
     content()
-    currentComposer.endProviders()
+    currentComposer.endProvider()
 }
 
 /**
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
index 1289e49..4144ccd 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
@@ -568,6 +568,44 @@
         }
     }
 
+    @Suppress("UNUSED_EXPRESSION")
+    @Test // Regression for b/292224893
+    fun testSingleInvalidatedProvider() = compositionTest {
+        val local1 = compositionLocalOf { 10 }
+        val local2 = compositionLocalOf { 20 }
+        val local3 = compositionLocalOf { 30 }
+        var state by mutableStateOf(0)
+
+        compose {
+            state
+            CompositionLocalProvider(local1 provides 11) {
+                state
+                CompositionLocalProvider(local2 provides 22) {
+                    state
+                    CompositionLocalProvider(local3 provides 33) {
+                        state
+                        assertEquals(11, local1.current)
+                        assertEquals(22, local2.current)
+                        assertEquals(33, local3.current)
+                    }
+                    assertEquals(11, local1.current)
+                    assertEquals(22, local2.current)
+                    assertEquals(30, local3.current)
+                }
+                assertEquals(11, local1.current)
+                assertEquals(20, local2.current)
+                assertEquals(30, local3.current)
+            }
+            assertEquals(10, local1.current)
+            assertEquals(20, local2.current)
+            assertEquals(30, local3.current)
+        }
+
+        state++
+
+        advance()
+    }
+
     @OptIn(ExperimentalCoroutinesApi::class)
     @Test
     fun testProvideAllLocals() = compositionTest {
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt
index d3d1a87..dcda328 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt
@@ -16,6 +16,7 @@
 
 package androidx.compose.runtime
 
+import androidx.compose.runtime.mock.Linear
 import androidx.compose.runtime.mock.MockViewValidator
 import androidx.compose.runtime.mock.View
 import androidx.compose.runtime.mock.ViewApplier
@@ -1541,6 +1542,50 @@
 
         assertEquals(state, lastSeen)
     }
+
+    @Test
+    fun movableContent_moveRow() = compositionTest {
+        var condition by mutableStateOf(true)
+
+        val movableContent1 = movableContentOf {
+            Text("First")
+        }
+        val movableContent2 = movableContentOf {
+            Text("Second")
+        }
+
+        compose {
+            if (condition) {
+                Linear {
+                    Linear {
+                        movableContent1()
+                    }
+                    movableContent2()
+                }
+            } else {
+                Linear {
+                    Linear {
+                        movableContent1()
+                    }
+                    movableContent2()
+                }
+            }
+        }
+
+        validate {
+            Linear {
+                Linear {
+                    Text("First")
+                }
+                Text("Second")
+            }
+        }
+
+        condition = false
+        expectChanges()
+
+        revalidate()
+    }
 }
 
 @Composable
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TestOwner.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TestOwner.kt
index 49bc878..d34d4bc 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TestOwner.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TestOwner.kt
@@ -93,8 +93,10 @@
             }
         }
 
-        return roots.flatMap {
-            it.semanticsOwner.getAllSemanticsNodes(mergingEnabled = !useUnmergedTree)
+        return testOwner.runOnUiThread {
+            roots.flatMap {
+                it.semanticsOwner.getAllSemanticsNodes(mergingEnabled = !useUnmergedTree)
+            }
         }
     }
 }
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index 91a2b5d1..f6bb7575a 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -1001,7 +1001,9 @@
   }
 
   @androidx.compose.runtime.Immutable public final class ImeOptions {
+    ctor @Deprecated public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
     ctor public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
+    method @Deprecated public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
     method public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
     method public boolean getAutoCorrect();
     method public int getCapitalization();
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index 91a2b5d1..f6bb7575a 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -1001,7 +1001,9 @@
   }
 
   @androidx.compose.runtime.Immutable public final class ImeOptions {
+    ctor @Deprecated public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
     ctor public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
+    method @Deprecated public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
     method public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
     method public boolean getAutoCorrect();
     method public int getCapitalization();
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/ImeOptions.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/ImeOptions.kt
index 487b949..8a45b44 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/ImeOptions.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/ImeOptions.kt
@@ -56,6 +56,25 @@
         val Default = ImeOptions()
     }
 
+    @Deprecated(
+        "Please use the new constructor that takes optional platformImeOptions parameter.",
+        level = DeprecationLevel.HIDDEN
+    )
+    constructor(
+        singleLine: Boolean = false,
+        capitalization: KeyboardCapitalization = KeyboardCapitalization.None,
+        autoCorrect: Boolean = true,
+        keyboardType: KeyboardType = KeyboardType.Text,
+        imeAction: ImeAction = ImeAction.Default,
+    ) : this(
+        singleLine = singleLine,
+        capitalization = capitalization,
+        autoCorrect = autoCorrect,
+        keyboardType = keyboardType,
+        imeAction = imeAction,
+        platformImeOptions = null
+    )
+
     fun copy(
         singleLine: Boolean = this.singleLine,
         capitalization: KeyboardCapitalization = this.capitalization,
@@ -74,6 +93,27 @@
         )
     }
 
+    @Deprecated(
+        "Please use the new copy function that takes optional platformImeOptions parameter.",
+        level = DeprecationLevel.HIDDEN
+    )
+    fun copy(
+        singleLine: Boolean = this.singleLine,
+        capitalization: KeyboardCapitalization = this.capitalization,
+        autoCorrect: Boolean = this.autoCorrect,
+        keyboardType: KeyboardType = this.keyboardType,
+        imeAction: ImeAction = this.imeAction
+    ): ImeOptions {
+        return ImeOptions(
+            singleLine = singleLine,
+            capitalization = capitalization,
+            autoCorrect = autoCorrect,
+            keyboardType = keyboardType,
+            imeAction = imeAction,
+            platformImeOptions = this.platformImeOptions
+        )
+    }
+
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
         if (other !is ImeOptions) return false
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt
index 48b3e9c..5377348 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt
@@ -599,7 +599,8 @@
             clock.setStateParameters(10.dp, 10.dp)
         }
         rule.runOnIdle {
-            assertEquals(2, clock.getAnimatedProperties().size)
+            // When initial == target state, no animation is active.
+            assertEquals(0, clock.getAnimatedProperties().size)
             clock.setStateParameters(20.dp, 40.dp)
         }
         rule.runOnIdle {
@@ -619,19 +620,8 @@
         rule.runOnIdle {
             // Default clock state.
             clock.getTransitions(100).let {
-                assertEquals(2, it.size)
-                it[0].let { info ->
-                    assertEquals(0, info.startTimeMillis)
-                    assertEquals(0, info.endTimeMillis)
-                    assertEquals(1, info.values.size)
-                    assertNotNull(info.specType)
-                }
-                it[1].let { info ->
-                    assertEquals(0, info.startTimeMillis)
-                    assertEquals(0, info.endTimeMillis)
-                    assertEquals(1, info.values.size)
-                    assertNotNull(info.specType)
-                }
+                // When initial == target state, no animation is active.
+                assertEquals(0, it.size)
             }
             // Change state
             clock.setStateParameters(20.dp, 40.dp)
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index 5ac963d..07a53a6 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -2175,14 +2175,14 @@
   @Deprecated @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public sealed interface LookaheadLayoutCoordinates extends androidx.compose.ui.layout.LayoutCoordinates {
   }
 
-  @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public interface LookaheadScope {
+  public interface LookaheadScope {
     method public androidx.compose.ui.layout.LayoutCoordinates getLookaheadScopeCoordinates(androidx.compose.ui.layout.Placeable.PlacementScope);
-    method public default long localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates, androidx.compose.ui.layout.LayoutCoordinates coordinates);
-    method public androidx.compose.ui.layout.LayoutCoordinates toLookaheadCoordinates(androidx.compose.ui.layout.LayoutCoordinates);
+    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default long localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates, androidx.compose.ui.layout.LayoutCoordinates coordinates);
+    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public androidx.compose.ui.layout.LayoutCoordinates toLookaheadCoordinates(androidx.compose.ui.layout.LayoutCoordinates);
   }
 
   public final class LookaheadScopeKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.compose.ui.ExperimentalComposeUiApi @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier intermediateLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.IntermediateMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measure);
   }
 
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index f3078e1..ec0b3c9 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -2178,14 +2178,14 @@
   @Deprecated @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public sealed interface LookaheadLayoutCoordinates extends androidx.compose.ui.layout.LayoutCoordinates {
   }
 
-  @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public interface LookaheadScope {
+  public interface LookaheadScope {
     method public androidx.compose.ui.layout.LayoutCoordinates getLookaheadScopeCoordinates(androidx.compose.ui.layout.Placeable.PlacementScope);
-    method public default long localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates, androidx.compose.ui.layout.LayoutCoordinates coordinates);
-    method public androidx.compose.ui.layout.LayoutCoordinates toLookaheadCoordinates(androidx.compose.ui.layout.LayoutCoordinates);
+    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default long localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates, androidx.compose.ui.layout.LayoutCoordinates coordinates);
+    method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public androidx.compose.ui.layout.LayoutCoordinates toLookaheadCoordinates(androidx.compose.ui.layout.LayoutCoordinates);
   }
 
   public final class LookaheadScopeKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.compose.ui.ExperimentalComposeUiApi @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier intermediateLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.IntermediateMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measure);
   }
 
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
index 93604d6..e905ca7 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
@@ -1953,11 +1953,12 @@
                     // This simulates a child that recomposes, for example due to a transition.
                     content(offset.value)
                 }
-                val assumeLayoutBeforeDraw = @Composable { _: Int ->
+                val assumeLayoutBeforeDraw = @Composable { value: Int ->
                     // This assumes a layout was done before the draw pass.
                     Layout(
                         content = {},
                         modifier = Modifier.drawBehind {
+                            assertEquals(offset.value, value)
                             assertTrue(laidOut)
                             latch.countDown()
                         }
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
index 7f3e41e..1725987 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
@@ -19,6 +19,7 @@
 package androidx.compose.ui.layout
 
 import androidx.activity.ComponentActivity
+import androidx.compose.animation.animateContentSize
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.AnimationVector2D
 import androidx.compose.animation.core.VectorConverter
@@ -28,6 +29,9 @@
 import androidx.compose.foundation.layout.Arrangement.Absolute.SpaceAround
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowColumn
+import androidx.compose.foundation.layout.FlowRow
 import androidx.compose.foundation.layout.IntrinsicSize
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
@@ -36,6 +40,7 @@
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredHeight
@@ -46,6 +51,7 @@
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.layout.widthIn
 import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.layout.wrapContentWidth
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
@@ -91,6 +97,7 @@
 import junit.framework.TestCase.assertTrue
 import kotlin.math.roundToInt
 import kotlin.random.Random
+import kotlin.test.assertNotNull
 import kotlinx.coroutines.launch
 import org.junit.Ignore
 import org.junit.Rule
@@ -1264,6 +1271,83 @@
         }
     }
 
+    @OptIn(ExperimentalLayoutApi::class)
+    @Test
+    fun testNestedLookaheadPlacement() {
+        var expanded by mutableStateOf(true)
+        var actualOffset: Offset? = null
+        var lookaheadOffset: Offset? = null
+        rule.setContent {
+            LookaheadScope {
+                FlowRow(
+                    modifier = Modifier.fillMaxSize(),
+                    horizontalArrangement = Arrangement.Center,
+                    verticalArrangement = Arrangement.Center,
+                    maxItemsInEachRow = 3
+                ) {
+                    Box(
+                        modifier = Modifier
+                            .animateContentSize()
+                            .widthIn(max = 600.dp)
+                            .background(Color.Red)
+                    ) {
+                        val height = if (expanded) 500.dp else 300.dp
+                        Box(
+                            modifier = Modifier
+                                .fillMaxWidth()
+                                .height(height)
+                        )
+                    }
+
+                    FlowColumn {
+                        Box(
+                            modifier = Modifier
+                                .size(200.dp)
+                                .layout { measurable, constraints ->
+                                    val placeable = measurable.measure(constraints)
+                                    layout(placeable.width, placeable.height) {
+                                        val coords = coordinates
+                                        if (coords != null) {
+                                            if (isLookingAhead) {
+                                                lookaheadOffset = coords
+                                                    .findRootCoordinates()
+                                                    .localLookaheadPositionOf(coords)
+                                            } else {
+                                                actualOffset = coords
+                                                    .findRootCoordinates()
+                                                    .localPositionOf(coords, Offset.Zero)
+                                            }
+                                        }
+                                        placeable.place(0, 0)
+                                    }
+                                }
+                                .wrapContentWidth()
+                                .heightIn(min = 156.dp)
+                                .background(Color.Blue)
+                        ) {
+                            Box(modifier = Modifier.size(200.dp))
+                        }
+                    }
+                }
+            }
+        }
+        rule.runOnIdle {
+            expanded = !expanded
+        }
+        rule.runOnIdle {
+            assertNotNull(actualOffset)
+            assertEquals(actualOffset, lookaheadOffset)
+            actualOffset = null
+            lookaheadOffset = null
+
+            expanded = !expanded
+        }
+        rule.runOnIdle {
+            assertNotNull(actualOffset)
+            assertEquals(actualOffset, lookaheadOffset)
+        }
+    }
+
     @Test
     fun grandparentQueryBaseline() {
         assertSameLayoutWithAndWithoutLookahead { modifier ->
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt
index ba4ee3b..1d331e9 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt
@@ -44,7 +44,6 @@
  *
  * @param content The child composable to be laid out.
  */
-@ExperimentalComposeUiApi
 @UiComposable
 @Composable
 fun LookaheadScope(content: @Composable @UiComposable LookaheadScope.() -> Unit) {
@@ -145,18 +144,19 @@
  *
  * @sample androidx.compose.ui.samples.LookaheadLayoutCoordinatesSample
  */
-@ExperimentalComposeUiApi
 interface LookaheadScope {
     /**
      * Converts a [LayoutCoordinates] into a [LayoutCoordinates] in the Lookahead coordinates space.
      * This is only applicable to child layouts within [LookaheadScope].
      */
+    @ExperimentalComposeUiApi
     fun LayoutCoordinates.toLookaheadCoordinates(): LayoutCoordinates
 
     /**
      * Returns the [LayoutCoordinates] of the [LookaheadScope]. This is
      * only accessible from [Placeable.PlacementScope] (i.e. during placement time).
      */
+    @ExperimentalComposeUiApi
     val Placeable.PlacementScope.lookaheadScopeCoordinates: LayoutCoordinates
 
     /**
@@ -165,6 +165,7 @@
      * [toLookaheadCoordinates], and 2) invoking [LayoutCoordinates.localPositionOf] with the
      * converted coordinates.
      */
+    @ExperimentalComposeUiApi
     fun LayoutCoordinates.localLookaheadPositionOf(coordinates: LayoutCoordinates) =
         this.toLookaheadCoordinates().localPositionOf(
             coordinates.toLookaheadCoordinates(),
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
index 4a1772b..3abc4d9 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
@@ -1274,6 +1274,7 @@
             val owner = layoutNode.requireOwner()
 
             if (!lookaheadLayoutPending && isPlaced) {
+                outerCoordinator.lookaheadDelegate!!.placeSelfApparentToRealOffset(position)
                 onNodePlaced()
             } else {
                 coordinatesAccessedDuringModifierPlacement = false
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LookaheadDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LookaheadDelegate.kt
index ba59c04..42c7d6b5 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LookaheadDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LookaheadDelegate.kt
@@ -151,14 +151,22 @@
         zIndex: Float,
         layerBlock: (GraphicsLayerScope.() -> Unit)?
     ) {
+        placeSelf(position)
+        if (isShallowPlacing) return
+        placeChildren()
+    }
+
+    private fun placeSelf(position: IntOffset) {
         if (this.position != position) {
             this.position = position
             layoutNode.layoutDelegate.lookaheadPassDelegate
                 ?.notifyChildrenUsingCoordinatesWhilePlacing()
             coordinator.invalidateAlignmentLinesFromPositionChange()
         }
-        if (isShallowPlacing) return
-        placeChildren()
+    }
+
+    internal fun placeSelfApparentToRealOffset(position: IntOffset) {
+        placeSelf(position + apparentToRealOffset)
     }
 
     protected open fun placeChildren() {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
index 120e248..9c53aa8 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
@@ -154,12 +154,16 @@
                 } else {
                     layoutNode.markLookaheadMeasurePending()
                     layoutNode.markMeasurePending()
-                    if (layoutNode.isPlacedInLookahead == true ||
-                        layoutNode.canAffectParentInLookahead
+                    if ((layoutNode.isPlacedInLookahead == true ||
+                            layoutNode.canAffectParentInLookahead) &&
+                        layoutNode.parent?.lookaheadMeasurePending != true
                     ) {
-                        if (layoutNode.parent?.lookaheadMeasurePending != true) {
-                            relayoutNodes.add(layoutNode, true)
-                        }
+                        relayoutNodes.add(layoutNode, true)
+                    } else if (
+                        (layoutNode.isPlaced || layoutNode.canAffectParent) &&
+                        layoutNode.parent?.measurePending != true
+                    ) {
+                        relayoutNodes.add(layoutNode, false)
                     }
                     !duringMeasureLayout
                 }
@@ -238,13 +242,17 @@
                     // dependency on lookahead layout.
                     layoutNode.markLookaheadLayoutPending()
                     layoutNode.markLayoutPending()
-                    if (layoutNode.isPlacedInLookahead == true) {
-                        val parent = layoutNode.parent
-                        if (parent?.lookaheadMeasurePending != true &&
-                            parent?.lookaheadLayoutPending != true
-                        ) {
-                            relayoutNodes.add(layoutNode, true)
-                        }
+
+                    val parent = layoutNode.parent
+                    if (layoutNode.isPlacedInLookahead == true &&
+                        parent?.lookaheadMeasurePending != true &&
+                        parent?.lookaheadLayoutPending != true
+                    ) {
+                        relayoutNodes.add(layoutNode, true)
+                    } else if (layoutNode.isPlaced &&
+                        parent?.layoutPending != true && parent?.measurePending != true
+                    ) {
+                        relayoutNodes.add(layoutNode, false)
                     }
                     !duringMeasureLayout
                 }
diff --git a/core/core-performance/samples/build.gradle b/core/core-performance/samples/build.gradle
index 0087990..ef28e3c 100644
--- a/core/core-performance/samples/build.gradle
+++ b/core/core-performance/samples/build.gradle
@@ -30,7 +30,7 @@
 }
 
 androidx {
-    name = "cSamples"
+    name = "Core Performance Samples"
     type = LibraryType.SAMPLES
     mavenVersion = LibraryVersions.CORE_PERFORMANCE
     inceptionYear = "2021"
diff --git a/core/core-performance/samples/src/main/java/androidx/core/performance/samples/Usage.kt b/core/core-performance/samples/src/main/java/androidx/core/performance/samples/Usage.kt
index ac4214b..62b5e9e 100644
--- a/core/core-performance/samples/src/main/java/androidx/core/performance/samples/Usage.kt
+++ b/core/core-performance/samples/src/main/java/androidx/core/performance/samples/Usage.kt
@@ -19,6 +19,7 @@
 package androidx.core.performance.samples
 
 import android.app.Application
+import android.os.Build
 import androidx.annotation.Sampled
 import androidx.core.performance.DefaultDevicePerformance
 import androidx.core.performance.DevicePerformance
@@ -36,6 +37,17 @@
         }
 
         fun doSomeThing() {
+            when {
+                devicePerformance.mediaPerformanceClass >= Build.VERSION_CODES.TIRAMISU -> {
+                    // Provide the most premium experience for highest performing devices
+                }
+                devicePerformance.mediaPerformanceClass == Build.VERSION_CODES.R -> {
+                    // Provide a high quality experience
+                }
+                else -> {
+                    // Remove extras to keep experience functional
+                }
+            }
         }
     }
 }
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt
index f1fff4d..302eac0 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt
@@ -70,7 +70,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackAnswerCall() {
         setUpV2Test()
         verifyAnswerCall()
@@ -84,7 +84,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackAnswerCall() {
         setUpV2Test()
         verifyRejectAnswerCall(Call.STATE_ACTIVE)
@@ -96,7 +96,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackHoldCall() {
         setUpV2Test()
         verifyRejectHoldCall()
@@ -108,7 +108,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackUnholdCall() {
         setUpV2Test()
         verifyRejectUnholdCall()
@@ -120,7 +120,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackDisconnectCall() {
         setUpV2Test()
         verifyRejectDisconnectCall(true)
@@ -132,7 +132,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackRejectCall() {
         setUpV2Test()
         verifyRejectDisconnectCall(false)
@@ -145,7 +145,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackDisconnectCall() {
         setUpV2Test()
         verifyDisconnectCall()
@@ -158,7 +158,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackHoldCall() {
         setUpV2Test()
         verifyHoldCall()
@@ -171,7 +171,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackUnholdCall() {
         setUpV2Test()
         verifyUnholdCall()
@@ -189,7 +189,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackAnswerCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyAnswerCall()
@@ -204,7 +204,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackAnswerCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyRejectAnswerCall(Call.STATE_DISCONNECTED)
@@ -217,7 +217,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackHoldCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyRejectHoldCall()
@@ -230,7 +230,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackUnholdCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyRejectUnholdCall()
@@ -243,7 +243,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackDisconnectCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyRejectDisconnectCall(true)
@@ -256,7 +256,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRejectCallControlCallbackRejectCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyRejectDisconnectCall(false)
@@ -270,7 +270,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackDisconnectCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyDisconnectCall()
@@ -284,7 +284,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackHoldCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyHoldCall()
@@ -298,7 +298,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackUnholdCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyUnholdCall()
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt
index 5992045..8abbb88 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt
@@ -81,7 +81,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicOutgoingCall() {
         setUpV2Test()
         runBlocking_addCallAndSetActive(TestUtils.OUTGOING_CALL_ATTRIBUTES)
@@ -93,7 +93,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicIncomingCall() {
         setUpV2Test()
         runBlocking_addCallAndSetActive(TestUtils.INCOMING_CALL_ATTRIBUTES)
@@ -105,7 +105,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testTogglingHoldOnActiveCall() {
         setUpV2Test()
         runBlocking_ToggleCallAsserts(TestUtils.OUTGOING_CALL_ATTRIBUTES)
@@ -118,7 +118,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testTogglingHoldOnActiveCall_NoHoldCapabilities() {
         setUpV2Test()
         assertFalse(TestUtils.OUTGOING_NO_HOLD_CAP_CALL_ATTRIBUTES
@@ -133,7 +133,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRequestEndpointChange() {
         setUpV2Test()
         runBlocking_RequestEndpointChangeAsserts()
@@ -146,7 +146,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testIsMuted() {
         setUpV2Test()
         verifyMuteStateChange()
@@ -158,7 +158,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackOperations_CallbackNotSet() {
         setUpV2Test()
         verifyAnswerCallFails_CallbackNotSet()
@@ -175,7 +175,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicOutgoingCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         runBlocking_addCallAndSetActive(TestUtils.OUTGOING_CALL_ATTRIBUTES)
@@ -188,7 +188,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicIncomingCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         runBlocking_addCallAndSetActive(TestUtils.INCOMING_CALL_ATTRIBUTES)
@@ -201,7 +201,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testTogglingHoldOnActiveCall_BackwardsCompat() {
         setUpBackwardsCompatTest()
         runBlocking_ToggleCallAsserts(TestUtils.OUTGOING_CALL_ATTRIBUTES)
@@ -215,7 +215,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testTogglingHoldOnActiveCall_NoHoldCapabilities_BackwardsCompat() {
         setUpBackwardsCompatTest()
         assertFalse(TestUtils.OUTGOING_NO_HOLD_CAP_CALL_ATTRIBUTES
@@ -231,7 +231,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testRequestEndpointChange_BackwardsCompat() {
         setUpBackwardsCompatTest()
         runBlocking_RequestEndpointChangeAsserts()
@@ -246,7 +246,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testIsMuted_BackwardsCompat() {
         setUpBackwardsCompatTest()
         verifyMuteStateChange()
@@ -259,7 +259,7 @@
      */
     @SdkSuppress(minSdkVersion = VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testBasicCallControlCallbackOperations_BackwardsCompat_CallbackNotSet() {
         setUpBackwardsCompatTest()
         verifyAnswerCallFails_CallbackNotSet()
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt
index 280fbdb..48bc53d 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt
@@ -78,7 +78,7 @@
      */
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testAddCallAssertModeInCommunication() {
         setUpV2Test()
         runBlocking_addCall_assertAudioModeInCommunication()
@@ -95,7 +95,7 @@
      */
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     @LargeTest
-    @Test
+    @Test(timeout = 10000)
     fun testAddCallAssertModeInCommunication_BackwardsCompat() {
         setUpBackwardsCompatTest()
         runBlocking_addCall_assertAudioModeInCommunication()
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt
index a18deea..4032e6e 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt
@@ -74,7 +74,7 @@
 
         private val JSON_KEY_CLIENT_DATA = "clientDataJSON"
         private val JSON_KEY_ATTESTATION_OBJ = "attestationObject"
-        private val JSON_KEY_AUTH_DATA = "authenticationData"
+        private val JSON_KEY_AUTH_DATA = "authenticatorData"
         private val JSON_KEY_SIGNATURE = "signature"
         private val JSON_KEY_USER_HANDLE = "userHandle"
         private val JSON_KEY_RESPONSE = "response"
diff --git a/development/referenceDocs/switcher.py b/development/referenceDocs/switcher.py
index 562d433..e73e4c6 100755
--- a/development/referenceDocs/switcher.py
+++ b/development/referenceDocs/switcher.py
@@ -81,14 +81,14 @@
       stub = doc.replace(java_source_abs_path, kotlin_source_abs_path)
       # Always add the switcher for java files, switch to the package summary if
       # the page itself doesn't exist in kotlin
-      slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\">/{}/' {}".format("\\n{% setvar page_path %}_page_path_{% endsetvar %}\\n{% setvar can_switch %}1{% endsetvar %}\\n{% include \"reference\/_java_switcher2.md\" %}",doc)
+      slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\"><\/div>/{}/' {}".format("\\n{% setvar page_path %}_page_path_{% endsetvar %}\\n{% setvar can_switch %}1{% endsetvar %}\\n{% include \"reference\/_java_switcher2.md\" %}",doc)
     else:
       file_path = doc[len(kotlin_ref_root)+1:]
       stub = doc.replace(kotlin_source_abs_path, java_source_abs_path)
       if (both):
-        slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\">/{}/' {}".format("\\n{% setvar page_path %}_page_path_{% endsetvar %}\\n{% setvar can_switch %}1{% endsetvar %}\\n{% include \"reference\/_kotlin_switcher2.md\" %}",doc)
+        slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\"><\/div>/{}/' {}".format("\\n{% setvar page_path %}_page_path_{% endsetvar %}\\n{% setvar can_switch %}1{% endsetvar %}\\n{% include \"reference\/_kotlin_switcher2.md\" %}",doc)
       else:
-        slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\">/{}/' {}".format("\\n{% include \"reference\/_kotlin_switcher2.md\" %}",doc)
+        slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\"><\/div>/{}/' {}".format("\\n{% include \"reference\/_kotlin_switcher2.md\" %}",doc)
 
     os.system(slug1)
     if both or java:
diff --git a/docs/api_guidelines/compat.md b/docs/api_guidelines/compat.md
index 6ec06be..a86ad2a 100644
--- a/docs/api_guidelines/compat.md
+++ b/docs/api_guidelines/compat.md
@@ -404,43 +404,75 @@
 ### Inter-process communication {#ipc}
 
 Protocols and data structures used for IPC must support interoperability between
-different versions of libraries and should be treated similarly to public API;
-however, AndroidX does not currently implement compatibility tracking for IPC.
-
-We recommend the following, in order of preference:
-
-1.  Stable AIDL if (1) your project lives partially in the Android platform and
-    has access to Stable AIDL build rules and (2) you need to support Android's
-    `Parcelable` data types. The AndroidX workflow **does not** provide Stable
-    AIDL compilation or compatibility checks, so these would need to happen in
-    the platform build and the resulting `.java` files would need to be copied
-    out.
-2.  Protobuf if (1) your project needs to persist data to disk or (2) you need
-    interoperability with systems already using Protobuf. Similar to Stable
-    AIDL, the AndroidX workflow **does not** provide built-in support Protobuf
-    compilation or compatibility checks. It is possible to use a Proto plug-in,
-    but you will be responsible for bundling the runtime and maintaining
-    compatibility on your own.
-3.  `Bundle` if you have a very simple data model that is unlikely to change in
-    the future. `Bundle` has the weakest type safety and compatibility
-    guarantees of any recommendation, and it has many caveats that make it a
-    poor choice.
-4.  `VersionedParcelable` if your project is already using Versioned Parcelable
-    and is aware of its compatibility constraints.
-
-We are currently evaluating Square's [Wire](https://github.com/square/wire) and
-Google's [gRPC](https://grpc.io/) libraries for recommendation. If either of
-these libraries meets your team's needs based on your own research, feel free to
-use them.
+different versions of libraries and should be treated similarly to public API.
 
 **Do not** design your own serialization mechanism or wire format for disk
 storage or inter-process communication. Preserving and verifying compatibility
 is difficult and error-prone.
 
-In all cases, **do not** expose your serialization mechanism in your API
-surface. Neither Stable AIDL nor Protobuf generate stable language APIs.
+**Do not** expose your serialization mechanism in your API surface. Neither
+Stable AIDL nor Protobuf generate stable language APIs.
 
-#### Annotating unstable IPC
+Generally, any communication prototcol, handshake, etc. must maintain
+compatibility consistent with SemVer guidelines. Consider how your protocol will
+handle addition and removal of operations or constants, compatibility-breaking
+changes, and other modifications without crashing either the host or client
+process.
+
+We recommend the following IPC mechanisms, in order of preference:
+
+#### Stable AIDL <a name="ipc-stableaidl"></a>
+
+Stable AIDL is used by the Android platform and AndroidX to provide a
+platform-native IPC mechanism with strong inter-process compatibility
+guarantees. It supports a subset of standard AIDL.
+
+Use Stable AIDL if your library:
+
+-   Needs to send and receive Android's `Parcelable` data types
+-   Communicates directly with the Android platform, System UI, or other AOSP
+    components *or* is likely to do so in the future
+
+**Do not** use Stable AIDL to persist data to disk.
+
+##### Using Stable AIDL {#ipc-stableaidl-using}
+
+To add Stable AIDL definitions to your project:
+
+1.  Add the Stable AIDL plugin to `build.gradle`:
+
+    ```
+    plugins {
+      id("androidx.stableaidl")
+    }
+    ```
+
+2.  Enable the AIDL build feature and specify an initial version for your Stable
+    AIDL interfaces in `build.gradle`:
+
+    ```
+    android {
+      buildFeatures {
+        aidl = true
+      }
+      buildTypes.all {
+        stableAidl {
+          version 1
+        }
+      }
+    }
+    ```
+
+3.  Migrate existing AIDL files or create new AIDL files under
+    `<project>/src/main/stableAidl`
+
+4.  Generate an initial set of Stable AIDL API tracking files by running
+
+    ```
+    ./gradlew :path:to:project:updateAidlApi
+    ```
+
+##### Annotating unstable AIDL {#ipc-stableaidl-unstable}
 
 Once an API that relies on an IPC contract ships to production in an app, the
 contract is locked in and must maintain compatibility to prevent crashing either
@@ -485,25 +517,29 @@
 annotations are required for Stable AIDL definition files under
 `src/stableAidl`.
 
-#### Parcelable {#ipc-parcelable}
+#### Protobuf <a name="ipc-protobuf"></a>
 
-**Do not** implement `Parcelable` for any class that may be used for IPC or
-otherwise exposed as public API. By default, `Parcelable` does not provide any
-compatibility guarantees and will result in crashes if fields are added or
-removed between library versions. If you are using Stable AIDL, you *may* use
-AIDL-defined parcelables for IPC but not public API.
+Protobuf is used by many Google applications and services to provide an IPC and
+disk persistence mechanism with strong inter-process compatibility guarantees.
 
-NOTE As of 2022/12/16, we are working on experimental support for compiling and
-tracking Stable AIDL definitions within the AndroidX workflow.
+Use Protobuf if your library:
 
-#### Protobuf {#ipc-protobuf}
+-   Communicates directly with other applications or services already using
+    Protobuf
+-   Your data structure is complex and likely to change over time - Needs to
+    persist data to disk
 
-Developers **should** use protocol buffers for most cases. See
-[Protobuf](#dependencies-protobuf) for more information on using protocol
-buffers in your library. **Do** use protocol buffers if your data structure is
-complex and likely to change over time. If your data includes `FileDescriptor`s,
-`Binder`s, or other platform-defined `Parcelable` data structures, they will
-need to be stored alongside the protobuf bytes in a `Bundle`.
+If your data includes `FileDescriptor`s, `Binder`s, or other platform-defined
+`Parcelable` data structures, consider using Stable AIDL instead. Protobuf
+cannot directly handle these types, and they will need to be stored alongside
+the serialized Protobuf bytes in a `Bundle`.
+
+See [Protobuf](#dependencies-protobuf) for more information on using protocol
+buffers in your library.
+
+WARNING While Protobuf is capable of maintaining inter-process compatibility,
+AndroidX does not currently provide compatibility tracking or enforcement.
+Library owners must perform their own validation.
 
 NOTE We are currently investigating the suitability of Square's
 [`wire` library](https://github.com/square/wire) for handling protocol buffers
@@ -511,12 +547,24 @@
 Libraries that expose their serialization mechanism in their API surface *will
 not be able to migrate*.
 
-#### Bundle {#ipc-bundle}
+#### Bundle <a name="ipc-bundle"></a>
 
-Developers **may** use `Bundle` in simple cases that require sending `Binder`s,
-`FileDescriptor`s, or platform `Parcelable`s across IPC
-([example](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/graphics/drawable/IconCompat.java;l=820)).
-Note that `Bundle` has several caveats:
+`Bundle` is used by the Android platform and AndroidX as a lightweight IPC
+mechanism. It has the weakest type safety and compatibility guarantees of any
+recommendation, and it has many caveats that make it a poor choice.
+
+In some cases, you may need to use a `Bundle` to wrap another IPC mechanism so
+that it can be passed through Android platform APIs, e.g. a `Bundle` that wraps
+a `byte[]` representing a serialized Protobuf.
+
+Use `Bundle` if your library:
+
+-   Has a very simple data model that is unlikely to change in the future
+-   Needs to send or receive `Binder`s, `FileDescriptor`s, or platform-defined
+    `Parcelable`s
+    ([example](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/graphics/drawable/IconCompat.java;l=820))
+
+Caveats for `Bundle` include:
 
 -   When running on Android S and below, accessing *any* entry in a `Bundle`
     will result in the platform attempting to deserialize *every* entry. This
@@ -535,9 +583,39 @@
     are responsible for providing their own system for guaranteeing wire format
     compatibility between versions.
 
-#### Communication protocols {#ipc-protocol}
+#### Versioned Parcelable <a name="ipc-versionedparcelable"></a>
 
-Any communication prototcol, handshake, etc. must maintain compatibility
-consistent with SemVer guidelines. Consider how your protocol will handle
-addition and removal of operations or constants, compatibility-breaking changes,
-and other modifications without crashing either the host or client process.
+`VersionedParcelable` is a deprecated library that was intended to provide
+compatibility guarantees around the Android platform's `Parcelable` class;
+however, the initial version contained bugs and it was not actively maintained.
+
+Use `VersionedParcelable` if your library:
+
+-   Is already using `VersionedParcelable` and you are aware of its
+    compatibility constraints
+
+**Do not** use `VersionedParcelable` in all other cases.
+
+#### Wire <a name="ipc-wire"></a>
+
+We are currently evaluating Square's [Wire](https://github.com/square/wire) as a
+front-end to Protobuf. If this library meets your team's needs based on your own
+research, feel free to use it.
+
+#### gRPC <a name="ipc-grpc"></a>
+
+Some clients have requested to use Google's [gRPC](https://grpc.io/) library to
+align with other Google products. It's okay to use gRPC for network
+communication or communication with libraries and services outside of AndroidX
+that are already using gRPC.
+
+**Do not** use gRPC to communicate between AndroidX libraries or with the
+Android platform.
+
+#### Parcelable <a name="ipc-parcelable"></a>
+
+**Do not** implement `Parcelable` for any class that may be used for IPC or
+otherwise exposed as public API. By default, `Parcelable` does not provide any
+compatibility guarantees and will result in crashes if fields are added or
+removed between library versions. If you are using Stable AIDL, you *may* use
+AIDL-defined parcelables for IPC but not public API.
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
index c2dea61..06749ed 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
@@ -25,6 +25,8 @@
 import android.view.animation.Animation
 import android.view.animation.AnimationUtils
 import android.view.animation.TranslateAnimation
+import android.window.BackEvent
+import androidx.activity.BackEventCompat
 import androidx.annotation.AnimRes
 import androidx.annotation.LayoutRes
 import androidx.core.view.ViewCompat
@@ -613,6 +615,64 @@
         assertThat(fragment1.requireView().parent).isNotNull()
     }
 
+    @Test
+    fun replaceOperationWithAnimationsThenSystemBack() {
+        waitForAnimationReady()
+        val fm1 = activityRule.activity.supportFragmentManager
+
+        val fragment1 = AnimationListenerFragment(R.layout.scene1)
+        fm1.beginTransaction()
+            .replace(R.id.fragmentContainer, fragment1, "1")
+            .addToBackStack(null)
+            .commit()
+        activityRule.waitForExecution()
+
+        val fragment2 = AnimationListenerFragment()
+
+        fm1.beginTransaction()
+            .setCustomAnimations(
+                R.anim.fade_in,
+                R.anim.fade_out,
+                R.anim.fade_in,
+                R.anim.fade_out
+            )
+            .replace(R.id.fragmentContainer, fragment2, "2")
+            .addToBackStack(null)
+            .commit()
+        activityRule.executePendingTransactions(fm1)
+
+        assertThat(fragment2.startAnimationLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+        // We need to wait for the exit animation to end
+        assertThat(fragment1.exitLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+
+        val dispatcher = activityRule.activity.onBackPressedDispatcher
+        activityRule.runOnUiThread {
+            dispatcher.dispatchOnBackStarted(BackEventCompat(0.1F, 0.1F, 0.1F, BackEvent.EDGE_LEFT))
+        }
+        activityRule.executePendingTransactions(fm1)
+        activityRule.runOnUiThread {
+            dispatcher.dispatchOnBackProgressed(
+                BackEventCompat(0.2F, 0.2F, 0.2F, BackEvent.EDGE_LEFT)
+            )
+            dispatcher.onBackPressed()
+        }
+        activityRule.executePendingTransactions(fm1)
+
+        assertThat(fragment2.startAnimationLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+        // Now fragment2 should be animating away
+        assertThat(fragment2.isAdded).isFalse()
+        assertThat(fm1.findFragmentByTag("2"))
+            .isEqualTo(null) // fragmentManager does not know about animating fragment
+        assertThat(fragment2.parentFragmentManager)
+            .isEqualTo(fm1) // but the animating fragment knows the fragmentManager
+
+        // We need to wait for the exit animation to end
+        assertThat(fragment2.exitLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+
+        // Make sure the original fragment was correctly readded to the container
+        assertThat(fragment1.requireView().parent).isNotNull()
+    }
+
     // When an animation is running on a Fragment's View, the view shouldn't be
     // prevented from being removed. There's no way to directly test this, so we have to
     // test to see if the animation is still running.
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt
index 58a7345..bd08997 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt
@@ -767,6 +767,14 @@
     }
 
     private class AnimationEffect(val animationInfo: AnimationInfo) : Effect() {
+        override fun onStart(container: ViewGroup) {
+            val operation: Operation = animationInfo.operation
+
+            val finalState = operation.finalState
+            if (finalState !== Operation.State.REMOVED) {
+                operation.effects.add(NoOpEffect(animationInfo))
+            }
+        }
         override fun onCommit(container: ViewGroup) {
             val context = container.context
             val operation: Operation = animationInfo.operation
@@ -780,10 +788,6 @@
                 // If the operation does not remove the view, we can't use a
                 // AnimationSet due that causing the introduction of visual artifacts (b/163084315).
                 viewToAnimate.startAnimation(anim)
-                // This means we can't use setAnimationListener() without overriding
-                // any listener that the Fragment has set themselves, so we
-                // just mark the special effect as complete immediately.
-                operation.effects.add(NoOpEffect(animationInfo))
             } else {
                 container.startViewTransition(viewToAnimate)
                 val animation: Animation = FragmentAnim.EndViewTransitionAnimation(anim,
@@ -968,7 +972,7 @@
                                 "SpecialEffectsController: Container $container has not been " +
                                     "laid out. Completing operation $operation")
                         }
-                        operation.effects.add(NoOpEffect(transitionInfo))
+                        transitionInfo.completeSpecialEffect()
                     } else {
                         transitionImpl.setListenerForTransitionEnd(
                             transitionInfo.operation.fragment,
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index ea26f32..54778a9 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -250,7 +250,7 @@
 reactiveStreams = { module = "org.reactivestreams:reactive-streams", version = "1.0.0" }
 retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
 retrofitConverterWire = { module = "com.squareup.retrofit2:converter-wire", version.ref = "retrofit" }
-robolectric = { module = "org.robolectric:robolectric", version = "4.9.2" }
+robolectric = { module = "org.robolectric:robolectric", version = "4.10.3" }
 rxjava2 = { module = "io.reactivex.rxjava2:rxjava", version = "2.2.9" }
 rxjava3 = { module = "io.reactivex.rxjava3:rxjava", version = "3.0.0" }
 shadow = { module = "gradle.plugin.com.github.johnrengelman:shadow", version = "7.1.1" }
diff --git a/libraryversions.toml b/libraryversions.toml
index 4972719..cdb7b5b 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -17,11 +17,11 @@
 CAMERA = "1.3.0-beta02"
 CAMERA_PIPE = "1.0.0-alpha01"
 CARDVIEW = "1.1.0-alpha01"
-CAR_APP = "1.4.0-alpha02"
+CAR_APP = "1.4.0-beta01"
 COLLECTION = "1.3.0-alpha05"
 COMPOSE = "1.6.0-alpha02"
 COMPOSE_COMPILER = "1.5.1"
-COMPOSE_MATERIAL3 = "1.2.0-alpha04"
+COMPOSE_MATERIAL3 = "1.2.0-alpha05"
 COMPOSE_MATERIAL3_ADAPTIVE = "1.0.0-alpha01"
 COMPOSE_RUNTIME_TRACING = "1.0.0-alpha03"
 CONSTRAINTLAYOUT = "2.2.0-alpha11"
@@ -29,7 +29,7 @@
 CONSTRAINTLAYOUT_CORE = "1.1.0-alpha11"
 CONTENTPAGER = "1.1.0-alpha01"
 COORDINATORLAYOUT = "1.3.0-alpha01"
-CORE = "1.12.0-beta01"
+CORE = "1.12.0-rc01"
 CORE_ANIMATION = "1.0.0-rc01"
 CORE_ANIMATION_TESTING = "1.0.0-rc01"
 CORE_APPDIGEST = "1.0.0-alpha01"
@@ -68,7 +68,7 @@
 GRAPHICS_FILTERS = "1.0.0-alpha01"
 GRAPHICS_SHAPES = "1.0.0-alpha03"
 GRIDLAYOUT = "1.1.0-beta02"
-HEALTH_CONNECT = "1.1.0-alpha03"
+HEALTH_CONNECT = "1.1.0-alpha04"
 HEALTH_SERVICES_CLIENT = "1.1.0-alpha01"
 HEIFWRITER = "1.1.0-alpha02"
 HILT = "1.1.0-alpha01"
@@ -151,11 +151,11 @@
 WEAR_INPUT_TESTING = "1.2.0-alpha03"
 WEAR_ONGOING = "1.1.0-alpha01"
 WEAR_PHONE_INTERACTIONS = "1.1.0-alpha04"
-WEAR_PROTOLAYOUT = "1.0.0-rc01"
+WEAR_PROTOLAYOUT = "1.1.0-alpha01"
 WEAR_REMOTE_INTERACTIONS = "1.1.0-alpha01"
-WEAR_TILES = "1.2.0-rc01"
+WEAR_TILES = "1.3.0-alpha01"
 WEAR_WATCHFACE = "1.2.0-alpha09"
-WEBKIT = "1.8.0-beta01"
+WEBKIT = "1.8.0-rc01"
 WINDOW = "1.2.0-beta01"
 WINDOW_EXTENSIONS = "1.2.0-rc01"
 WINDOW_EXTENSIONS_CORE = "1.1.0-alpha01"
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.java b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.java
deleted file mode 100644
index ac0474a..0000000
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 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.lifecycle.observers;
-
-import androidx.lifecycle.Lifecycle;
-
-@SuppressWarnings("deprecation")
-public class DerivedWithOverriddenMethodsWithLfAnnotation extends Base {
-
-    @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
-    @Override
-    public void onCreate() {
-        super.onCreate();
-    }
-}
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.kt
similarity index 74%
copy from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
copy to lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.kt
index 31d0e6f..f239dfc 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.kt
@@ -13,15 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package androidx.lifecycle.observers
 
-package androidx.lifecycle.observers;
+import androidx.lifecycle.Lifecycle
 
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
+@Suppress("DEPRECATION")
+class DerivedWithOverriddenMethodsWithLfAnnotation : Base() {
     @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
-    void onCreate();
+    override fun onCreate() {
+        super.onCreate()
+    }
 }
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.kt
similarity index 74%
rename from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
rename to lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.kt
index 31d0e6f..fb49485 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.kt
@@ -13,15 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package androidx.lifecycle.observers
 
-package androidx.lifecycle.observers;
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleObserver
 
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
+@Suppress("DEPRECATION")
+interface Interface1 : LifecycleObserver {
     @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
-    void onCreate();
+    fun onCreate()
 }
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.java b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.kt
similarity index 74%
rename from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.java
rename to lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.kt
index f272601..b3faa538a 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.java
+++ b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.kt
@@ -13,18 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package androidx.lifecycle.observers
 
-package androidx.lifecycle.observers;
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleObserver
 
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-
-@SuppressWarnings("deprecation")
-public interface Interface2 extends LifecycleObserver {
-
+@Suppress("DEPRECATION")
+interface Interface2 : LifecycleObserver {
     @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
-    void onCreate();
+    fun onCreate()
 
     @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
-    void onDestroy();
+    fun onDestroy()
 }
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
index 704d543..3c7ef5e 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
@@ -15,6 +15,7 @@
  */
 
 import androidx.build.LibraryType
+import javax.inject.Inject
 
 plugins {
     id("AndroidXPlugin")
@@ -22,6 +23,72 @@
     id("org.jetbrains.kotlin.android")
 }
 
+abstract class BundleTestSdkDexTask extends DefaultTask {
+
+    @InputFiles
+    @PathSensitive(PathSensitivity.NAME_ONLY)
+    abstract ConfigurableFileCollection getTestSdkApkFolders()
+
+    @OutputDirectory
+    abstract DirectoryProperty getOutputDir()
+
+    @Inject
+    abstract FileSystemOperations getFileSystemOperations()
+
+    @Inject
+    abstract ArchiveOperations getArchiveOperations()
+
+    @TaskAction
+    def exec() {
+        for (File folder : testSdkApkFolders.files) {
+            for (File file : folder.listFiles()) {
+                String fileName = file.name
+                if (!fileName.endsWith(".apk")) {
+                    continue
+                }
+
+                int projectNameEnd = fileName.indexOf("-")
+                String projectName = projectNameEnd > 0 ? fileName.substring(0, projectNameEnd) : fileName
+
+                fileSystemOperations.copy {
+                    from(archiveOperations.zipTree(file))
+                    into(outputDir.dir("test-sdks/$projectName/"))
+                    include('*.dex')
+                }
+            }
+        }
+    }
+}
+
+def bundleTestSdkDexTaskProvider = tasks.register("bundleTestSdkDexTask", BundleTestSdkDexTask) {
+    description("Bundle DEX from the androidTestBundleDex configuration into assets folder")
+
+    def configuration = configurations.getByName("androidTestBundleDex")
+    testSdkApkFolders.from(configuration.incoming.artifactView {}.files)
+}
+
+androidComponents {
+    onVariants(selector().withBuildType("debug")) {
+        androidTest.sources.assets.addGeneratedSourceDirectory(
+                bundleTestSdkDexTaskProvider,
+                BundleTestSdkDexTask::getOutputDir
+        )
+    }
+}
+
+configurations {
+    androidTestBundleDex {
+        canBeConsumed = false
+        canBeResolved = true
+        attributes {
+            attribute(
+                    LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
+                    objects.named(LibraryElements, "testSdkApk")
+            )
+        }
+    }
+}
+
 dependencies {
     api(libs.kotlinStdlib)
     api(libs.kotlinCoroutinesCore)
@@ -48,6 +115,8 @@
 
     androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(libs.dexmakerMockitoInline, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+
+    androidTestBundleDex(project(":privacysandbox:sdkruntime:test-sdks:current"))
 }
 
 android {
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkProviderTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkProviderTest.kt
index 4149ac0..09f256a 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkProviderTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkProviderTest.kt
@@ -19,7 +19,6 @@
 import android.os.Binder
 import android.os.Bundle
 import android.os.IBinder
-import android.view.View
 import androidx.lifecycle.Lifecycle
 import androidx.privacysandbox.sdkruntime.client.EmptyActivity
 import androidx.privacysandbox.sdkruntime.client.TestActivityHolder
@@ -31,7 +30,6 @@
 import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
 import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
 import androidx.privacysandbox.sdkruntime.core.SandboxedSdkInfo
-import androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
 import androidx.privacysandbox.sdkruntime.core.Versions
 import androidx.privacysandbox.sdkruntime.core.activity.SdkSandboxActivityHandlerCompat
 import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
@@ -227,60 +225,6 @@
         assertThat(controller.sdkActivityHandlers[token]).isNull()
     }
 
-    class CurrentVersionProviderLoadTest : SandboxedSdkProviderCompat() {
-        @JvmField
-        var onLoadSdkBinder: Binder? = null
-
-        @JvmField
-        var lastOnLoadSdkParams: Bundle? = null
-
-        @JvmField
-        var isBeforeUnloadSdkCalled = false
-
-        @Throws(LoadSdkCompatException::class)
-        override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
-            val result = CurrentVersionSdkTest(context!!)
-            onLoadSdkBinder = result
-
-            lastOnLoadSdkParams = params
-            if (params.getBoolean("needFail", false)) {
-                throw LoadSdkCompatException(RuntimeException(), params)
-            }
-            return SandboxedSdkCompat(result)
-        }
-
-        override fun beforeUnloadSdk() {
-            isBeforeUnloadSdkCalled = true
-        }
-
-        override fun getView(
-            windowContext: Context,
-            params: Bundle,
-            width: Int,
-            height: Int
-        ): View {
-            return View(windowContext)
-        }
-    }
-
-    @Suppress("unused") // Reflection calls
-    internal class CurrentVersionSdkTest(
-        private val context: Context
-    ) : Binder() {
-        fun getSandboxedSdks(): List<SandboxedSdkCompat> =
-            SdkSandboxControllerCompat.from(context).getSandboxedSdks()
-
-        fun getAppOwnedSdkSandboxInterfaces(): List<AppOwnedSdkSandboxInterfaceCompat> =
-            SdkSandboxControllerCompat.from(context).getAppOwnedSdkSandboxInterfaces()
-
-        fun registerSdkSandboxActivityHandler(handler: SdkSandboxActivityHandlerCompat): IBinder =
-            SdkSandboxControllerCompat.from(context).registerSdkSandboxActivityHandler(handler)
-
-        fun unregisterSdkSandboxActivityHandler(handler: SdkSandboxActivityHandlerCompat) {
-            SdkSandboxControllerCompat.from(context).unregisterSdkSandboxActivityHandler(handler)
-        }
-    }
-
     internal class TestClassLoaderFactory(
         private val testStorage: TestLocalSdkStorage
     ) : SdkLoader.ClassLoaderFactory {
@@ -364,35 +308,23 @@
                 )
             }
 
-            // add SDK loaded from test sources
+            val currentVersionSdk = TestSdkInfo(
+                Versions.API_VERSION,
+                "test-sdks/current/classes.dex",
+                "androidx.privacysandbox.sdkruntime.testsdk.current.CompatProvider"
+            )
             val controller = TestStubController()
+
+            val loadedSdk = loadTestSdkFromAssets(currentVersionSdk.localSdkConfig, controller)
+            assertThat(loadedSdk.extractApiVersion())
+                .isEqualTo(currentVersionSdk.apiVersion)
+
             add(
                 arrayOf(
-                    "BuiltFromSource",
-                    Versions.API_VERSION,
+                    currentVersionSdk.localSdkConfig.dexPaths[0],
+                    currentVersionSdk.apiVersion,
                     controller,
-                    loadTestSdkFromSource(controller),
-                )
-            )
-        }
-
-        private fun loadTestSdkFromSource(controller: TestStubController): LocalSdkProvider {
-            val sdkLoader = SdkLoader(
-                object : SdkLoader.ClassLoaderFactory {
-                    override fun createClassLoaderFor(
-                        sdkConfig: LocalSdkConfig,
-                        parent: ClassLoader
-                    ): ClassLoader = javaClass.classLoader!!
-                },
-                ApplicationProvider.getApplicationContext(),
-                controller
-            )
-
-            return sdkLoader.loadSdk(
-                LocalSdkConfig(
-                    packageName = "test.CurrentVersionProviderLoadTest",
-                    dexPaths = emptyList(),
-                    entryPoint = CurrentVersionProviderLoadTest::class.java.name
+                    loadedSdk
                 )
             )
         }
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt
index e08530e..2d2d2a7 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt
@@ -224,6 +224,9 @@
 
         val targetBaseDataDir = Api24.dataDir(baseContext)
         val targetSharedPreferencesDir = File(targetBaseDataDir, "shared_prefs")
+        if (!targetSharedPreferencesDir.exists()) {
+            targetSharedPreferencesDir.mkdir()
+        }
 
         if (sourceSharedPreferencesDir == targetSharedPreferencesDir) {
             return true
diff --git a/privacysandbox/sdkruntime/test-sdks/current/build.gradle b/privacysandbox/sdkruntime/test-sdks/current/build.gradle
new file mode 100644
index 0000000..c69ab15
--- /dev/null
+++ b/privacysandbox/sdkruntime/test-sdks/current/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * 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 com.android.build.api.artifact.SingleArtifact
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.application")
+    id("org.jetbrains.kotlin.android")
+}
+
+android {
+    namespace "androidx.privacysandbox.sdkruntime.testsdk.current"
+}
+
+dependencies {
+    implementation(project(":privacysandbox:sdkruntime:sdkruntime-core"))
+}
+
+/*
+ * Allow integration tests to consume the APK produced by this project
+ */
+configurations {
+    testSdkApk {
+        canBeConsumed = true
+        canBeResolved = false
+        attributes {
+            attribute(
+                    LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
+                    objects.named(LibraryElements, "testSdkApk")
+            )
+        }
+    }
+}
+
+androidComponents {
+    beforeVariants(selector().all()) { enabled = buildType == 'release' }
+    onVariants(selector().all().withBuildType("release"), { variant ->
+        artifacts {
+            testSdkApk(variant.artifacts.get(SingleArtifact.APK.INSTANCE))
+        }
+    })
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/test-sdks/current/src/main/AndroidManifest.xml b/privacysandbox/sdkruntime/test-sdks/current/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8de5974
--- /dev/null
+++ b/privacysandbox/sdkruntime/test-sdks/current/src/main/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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">
+</manifest>
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/test-sdks/current/src/main/java/androidx/privacysandbox/sdkruntime/testsdk/current/CompatProvider.kt b/privacysandbox/sdkruntime/test-sdks/current/src/main/java/androidx/privacysandbox/sdkruntime/testsdk/current/CompatProvider.kt
new file mode 100644
index 0000000..03f31ea
--- /dev/null
+++ b/privacysandbox/sdkruntime/test-sdks/current/src/main/java/androidx/privacysandbox/sdkruntime/testsdk/current/CompatProvider.kt
@@ -0,0 +1,83 @@
+/*
+ * 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.sdkruntime.testsdk.current
+
+import android.content.Context
+import android.os.Binder
+import android.os.Bundle
+import android.os.IBinder
+import android.view.View
+import androidx.privacysandbox.sdkruntime.core.AppOwnedSdkSandboxInterfaceCompat
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
+import androidx.privacysandbox.sdkruntime.core.activity.SdkSandboxActivityHandlerCompat
+import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
+
+@Suppress("unused") // Reflection usage from tests in privacysandbox:sdkruntime:sdkruntime-client
+class CompatProvider : SandboxedSdkProviderCompat() {
+    @JvmField
+    var onLoadSdkBinder: Binder? = null
+
+    @JvmField
+    var lastOnLoadSdkParams: Bundle? = null
+
+    @JvmField
+    var isBeforeUnloadSdkCalled = false
+
+    @Throws(LoadSdkCompatException::class)
+    override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
+        val result = CurrentVersionSdkTest(context!!)
+        onLoadSdkBinder = result
+
+        lastOnLoadSdkParams = params
+        if (params.getBoolean("needFail", false)) {
+            throw LoadSdkCompatException(RuntimeException(), params)
+        }
+        return SandboxedSdkCompat(result)
+    }
+
+    override fun beforeUnloadSdk() {
+        isBeforeUnloadSdkCalled = true
+    }
+
+    override fun getView(
+        windowContext: Context,
+        params: Bundle,
+        width: Int,
+        height: Int
+    ): View {
+        return View(windowContext)
+    }
+
+    internal class CurrentVersionSdkTest(
+        private val context: Context
+    ) : Binder() {
+        fun getSandboxedSdks(): List<SandboxedSdkCompat> =
+            SdkSandboxControllerCompat.from(context).getSandboxedSdks()
+
+        fun getAppOwnedSdkSandboxInterfaces(): List<AppOwnedSdkSandboxInterfaceCompat> =
+            SdkSandboxControllerCompat.from(context).getAppOwnedSdkSandboxInterfaces()
+
+        fun registerSdkSandboxActivityHandler(handler: SdkSandboxActivityHandlerCompat): IBinder =
+            SdkSandboxControllerCompat.from(context).registerSdkSandboxActivityHandler(handler)
+
+        fun unregisterSdkSandboxActivityHandler(handler: SdkSandboxActivityHandlerCompat) {
+            SdkSandboxControllerCompat.from(context).unregisterSdkSandboxActivityHandler(handler)
+        }
+    }
+}
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewSmoothScrollToPositionTest.kt b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewSmoothScrollToPositionTest.kt
index 6a10b3d..c10f74d 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewSmoothScrollToPositionTest.kt
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewSmoothScrollToPositionTest.kt
@@ -158,12 +158,19 @@
             "onStop should be called eventually",
             calledOnStop.await(30, TimeUnit.SECONDS)
         )
-        Assert.assertNotNull(
-            "smoothScrollToPosition should succeed " +
-                "(first visible item: " + layoutManager.findFirstVisibleItemPosition() +
-                ", last visible item: " + layoutManager.findLastVisibleItemPosition() + ")",
-            recyclerView.findViewHolderForLayoutPosition(targetPosition)
-        )
+
+        // This needs to be run on the UI thread 1) due to inspecting the results of operations
+        // (such as layout) that may occur after the latch is counted down, and 2) in order to
+        // ensure that it doesn't run concurrently with operations on the UI thread that might
+        // affect the state.
+        mActivityTestRule.runOnUiThread {
+            Assert.assertNotNull(
+                "smoothScrollToPosition should succeed " +
+                    "(first visible item: " + layoutManager.findFirstVisibleItemPosition() +
+                    ", last visible item: " + layoutManager.findLastVisibleItemPosition() + ")",
+                recyclerView.findViewHolderForLayoutPosition(targetPosition)
+            )
+        }
     }
 
     private fun setup(
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/MusicDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/MusicDao.kt
index 5753602..426a4f9 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/MusicDao.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/MusicDao.kt
@@ -13,6 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+@file:Suppress("DEPRECATION") // For @MapInfo
+
 package androidx.room.integration.kotlintestapp.dao
 
 import androidx.collection.ArrayMap
@@ -22,6 +25,7 @@
 import androidx.room.Dao
 import androidx.room.Delete
 import androidx.room.Insert
+import androidx.room.MapColumn
 import androidx.room.MapInfo
 import androidx.room.Query
 import androidx.room.RawQuery
@@ -374,4 +378,42 @@
     @Transaction
     @Query("SELECT * FROM Playlist WHERE mPlaylistId = :id")
     fun getPlaylistsWithSongsFlow(id: Int): Flow<PlaylistWithSongs>
+
+    @Query("SELECT * FROM Artist JOIN Song ON Artist.mArtistName = Song.mArtist")
+    @RewriteQueriesToDropUnusedColumns
+    fun artistNameToSongsMapColumn():
+        Map<@MapColumn(columnName = "mArtistName") String,
+            List<@MapColumn(columnName = "mReleasedYear") Int>>
+
+    @Query(
+        """
+        SELECT * FROM Image
+        LEFT JOIN Artist ON Image.mArtistInImage = Artist.mArtistName
+        LEFT JOIN Album ON Artist.mArtistName = Album.mAlbumArtist
+        LEFT JOIN Song ON Album.mAlbumName = Song.mAlbum
+        """
+    )
+    @RewriteQueriesToDropUnusedColumns
+    fun getImageYearToArtistToAlbumsToSongsMapColumn():
+        Map<@MapColumn(columnName = "mImageYear") Long, Map<Artist,
+            Map<@MapColumn(columnName = "mAlbumName") String, List<Song>>>>
+
+    @Query(
+        """
+        SELECT * FROM Image
+        LEFT JOIN Artist ON Image.mArtistInImage = Artist.mArtistName
+        LEFT JOIN Album ON Artist.mArtistName = Album.mAlbumArtist
+        LEFT JOIN Song ON Album.mAlbumName = Song.mAlbum
+        """
+    )
+    @RewriteQueriesToDropUnusedColumns
+    fun getImageYearToArtistToAlbumsToSongsMultiMapColumn():
+        Map<Image, Map<Artist, Map<@MapColumn(columnName = "mAlbumName") String,
+            List<@MapColumn(columnName = "mReleasedYear") Int>>>>
+
+    @RawQuery
+    @RewriteQueriesToDropUnusedColumns
+    fun getImageYearToArtistToAlbumsToSongsMultiMapColumn(query: SupportSQLiteQuery):
+        Map<Image, Map<Artist, Map<@MapColumn(columnName = "mAlbumName") String,
+            List<@MapColumn(columnName = "mReleasedYear") Int>>>>
 }
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/AmbiguousColumnResolverTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/AmbiguousColumnResolverTest.kt
index 3647b62..b11a259 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/AmbiguousColumnResolverTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/AmbiguousColumnResolverTest.kt
@@ -24,7 +24,7 @@
 import androidx.room.Embedded
 import androidx.room.Entity
 import androidx.room.Insert
-import androidx.room.MapInfo
+import androidx.room.MapColumn
 import androidx.room.PrimaryKey
 import androidx.room.Query
 import androidx.room.Relation
@@ -103,7 +103,7 @@
     }
 
     @Test
-    fun withMapInfo() {
+    fun withMapColumn() {
         dao.getUserIdAndComments().let { userIdAndComments ->
             assertThat(userIdAndComments[1]).containsExactly(comment1)
             assertThat(userIdAndComments[2]).containsExactly(comment2, comment3)
@@ -198,32 +198,31 @@
         // Suppress on CURSOR_MISMATCH is because @RewriteQueriesToDropUnusedColumns does not
         // rewrite queries with duplicate columns.
         @Suppress(RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT)
-        @MapInfo(keyColumn = "id", keyTable = "User")
         @Query("SELECT * FROM User JOIN Comment ON User.id = Comment.userId")
-        fun getUserIdAndComments(): Map<Int, List<Comment>>
+        fun getUserIdAndComments(): Map<@MapColumn("id") Int, List<Comment>>
 
         // This works because User.id is in the projection first, but if swapped with Comment.*
         // it would return bad results, hence the AMBIGUOUS_COLUMN_IN_RESULT.
         @Suppress(RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT)
-        @MapInfo(keyColumn = "id", keyTable = "User")
         @Query("SELECT User.id, Comment.* FROM User JOIN Comment ON User.id = Comment.userId")
-        fun getUserIdAndCommentsTableOrderSwapped(): Map<Int, List<Comment>>
+        fun getUserIdAndCommentsTableOrderSwapped():
+            Map<@MapColumn("id") Int, List<Comment>>
 
         // Aliasing the single ambiguous column is good.
-        @MapInfo(keyColumn = "user_id")
         @Query("""
             SELECT Comment.*, User.id as user_id
             FROM User JOIN Comment ON User.id = Comment.userId
             """)
-        fun getUserIdAliasedAndCommentsTableOrderSwapped(): Map<Int, List<Comment>>
+        fun getUserIdAliasedAndCommentsTableOrderSwapped():
+            Map<@MapColumn("user_id")Int, List<Comment>>
 
-        @MapInfo(keyColumn = "id", keyTable = "User", valueColumn = "commentsCount")
         @Query("""
             SELECT User.id, count(*) AS commentsCount
             FROM User JOIN Comment ON User.id = Comment.userId
             GROUP BY User.id
             """)
-        fun getUserIdAndAmountOfComments(): Map<Int, Int>
+        fun getUserIdAndAmountOfComments():
+            Map<@MapColumn("id") Int, @MapColumn("commentsCount") Int>
 
         @Query("SELECT * FROM User LEFT JOIN Comment ON User.id = Comment.userId")
         fun getLeftJoinUserCommentMap(): Map<User, List<Comment>>
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/MultimapQueryTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/MultimapQueryTest.kt
index c44486f..6310e19 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/MultimapQueryTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/MultimapQueryTest.kt
@@ -59,6 +59,9 @@
 
 /**
  * Tests multimap return type for JOIN statements.
+ *
+ * Deprecation has been suppressed for @MapInfo. We still need these tests, but the annotation
+ * is deprecated.
  */
 @MediumTest
 @RunWith(AndroidJUnit4::class)
@@ -1334,6 +1337,176 @@
         ).isEmpty()
     }
 
+    @Test
+    fun testDoubleNestedMapWithMapColumnKeyLeftJoin() {
+        mMusicDao.addArtists(mRhcp, mAcDc, mPinkFloyd)
+        mMusicDao.addAlbums(
+            mStadiumArcadium,
+            mCalifornication,
+            mTheDarkSideOfTheMoon,
+            mHighwayToHell,
+            mDreamland
+        )
+        mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mRhcpSong3)
+        mMusicDao.addImages(mPinkFloydAlbumCover, mRhcpAlbumCover, mTheClashAlbumCover)
+
+        val doubleNestedMap = mMusicDao.getImageYearToArtistToAlbumsToSongsMultiMapColumn()
+        val rhcpImageMap = doubleNestedMap.getValue(mRhcpAlbumCover)
+        val rhcpMap = rhcpImageMap.getValue(mRhcp)
+        val stadiumArcadiumList = rhcpMap[mStadiumArcadium.mAlbumName]
+        val californicationList = rhcpMap[mCalifornication.mAlbumName]
+
+        val stadiumArcadiumExpectedList = listOf(mRhcpSong1.mReleasedYear, mRhcpSong2.mReleasedYear)
+        val californicationExpectedList = listOf(mRhcpSong3.mReleasedYear)
+
+        assertThat(doubleNestedMap.keys).containsExactlyElementsIn(
+            listOf(
+                mPinkFloydAlbumCover,
+                mRhcpAlbumCover,
+                mTheClashAlbumCover
+            )
+        )
+        assertThat(rhcpImageMap.keys).containsExactly(mRhcp)
+        assertThat(rhcpMap.keys).containsExactlyElementsIn(
+            listOf(mCalifornication.mAlbumName, mStadiumArcadium.mAlbumName)
+        )
+        assertThat(stadiumArcadiumList).containsExactlyElementsIn(stadiumArcadiumExpectedList)
+        assertThat(californicationList).containsExactlyElementsIn(californicationExpectedList)
+
+        // LEFT JOIN Checks
+        assertThat(doubleNestedMap).containsKey(mTheClashAlbumCover)
+        assertThat(doubleNestedMap[mTheClashAlbumCover]).isEmpty()
+        assertThat(doubleNestedMap).containsKey(mPinkFloydAlbumCover)
+        assertThat(doubleNestedMap[mPinkFloydAlbumCover]).containsKey(mPinkFloyd)
+        assertThat(doubleNestedMap[mPinkFloydAlbumCover]!![mPinkFloyd])
+            .containsKey(mTheDarkSideOfTheMoon.mAlbumName)
+        assertThat(
+            doubleNestedMap[mPinkFloydAlbumCover]
+            !![mPinkFloyd]
+            !![mTheDarkSideOfTheMoon.mAlbumName]
+        ).isEmpty()
+    }
+
+    @Test
+    fun testDoubleNestedMapWithMapColumnKeyLeftJoinRawQuery() {
+        mMusicDao.addArtists(mRhcp, mAcDc, mPinkFloyd)
+        mMusicDao.addAlbums(
+            mStadiumArcadium,
+            mCalifornication,
+            mTheDarkSideOfTheMoon,
+            mHighwayToHell,
+            mDreamland
+        )
+        mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mRhcpSong3)
+        mMusicDao.addImages(mPinkFloydAlbumCover, mRhcpAlbumCover, mTheClashAlbumCover)
+
+        val doubleNestedMap = mMusicDao.getImageYearToArtistToAlbumsToSongsMultiMapColumn(
+            SimpleSQLiteQuery(
+                """
+                SELECT * FROM Image
+                LEFT JOIN Artist ON Image.mArtistInImage = Artist.mArtistName
+                LEFT JOIN Album ON Artist.mArtistName = Album.mAlbumArtist
+                LEFT JOIN Song ON Album.mAlbumName = Song.mAlbum
+                """
+            )
+        )
+        val rhcpImageMap = doubleNestedMap.getValue(mRhcpAlbumCover)
+        val rhcpMap = rhcpImageMap.getValue(mRhcp)
+        val stadiumArcadiumList = rhcpMap[mStadiumArcadium.mAlbumName]
+        val californicationList = rhcpMap[mCalifornication.mAlbumName]
+
+        val stadiumArcadiumExpectedList = listOf(mRhcpSong1.mReleasedYear, mRhcpSong2.mReleasedYear)
+        val californicationExpectedList = listOf(mRhcpSong3.mReleasedYear)
+
+        assertThat(doubleNestedMap.keys).containsExactlyElementsIn(
+            listOf(
+                mPinkFloydAlbumCover,
+                mRhcpAlbumCover,
+                mTheClashAlbumCover
+            )
+        )
+        assertThat(rhcpImageMap.keys).containsExactly(mRhcp)
+        assertThat(rhcpMap.keys).containsExactlyElementsIn(
+            listOf(mCalifornication.mAlbumName, mStadiumArcadium.mAlbumName)
+        )
+        assertThat(stadiumArcadiumList).containsExactlyElementsIn(stadiumArcadiumExpectedList)
+        assertThat(californicationList).containsExactlyElementsIn(californicationExpectedList)
+
+        // LEFT JOIN Checks
+        assertThat(doubleNestedMap).containsKey(mTheClashAlbumCover)
+        assertThat(doubleNestedMap[mTheClashAlbumCover]).isEmpty()
+        assertThat(doubleNestedMap).containsKey(mPinkFloydAlbumCover)
+        assertThat(doubleNestedMap[mPinkFloydAlbumCover]).containsKey(mPinkFloyd)
+        assertThat(doubleNestedMap[mPinkFloydAlbumCover]!![mPinkFloyd])
+            .containsKey(mTheDarkSideOfTheMoon.mAlbumName)
+        assertThat(
+            doubleNestedMap[mPinkFloydAlbumCover]
+            !![mPinkFloyd]
+            !![mTheDarkSideOfTheMoon.mAlbumName]
+        ).isEmpty()
+    }
+
+    @Test
+    fun testStringToListOfSongsMapColumn() {
+        mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mPinkFloydSong1)
+        mMusicDao.addArtists(mRhcp, mAcDc, mTheClash, mPinkFloyd)
+        val artistNameToSongsMap: Map<String, List<Int>> = mMusicDao.artistNameToSongsMapColumn()
+        assertThat(artistNameToSongsMap.containsKey("Pink Floyd")).isTrue()
+        assertThat(artistNameToSongsMap["Red Hot Chili Peppers"]).containsExactlyElementsIn(
+            listOf(mRhcpSong1.mReleasedYear, mRhcpSong2.mReleasedYear)
+        )
+    }
+
+    @Test
+    fun testDoubleNestedMapWithOneMapColumn() {
+        mMusicDao.addArtists(mRhcp, mAcDc, mPinkFloyd)
+        mMusicDao.addAlbums(
+            mStadiumArcadium,
+            mCalifornication,
+            mTheDarkSideOfTheMoon,
+            mHighwayToHell,
+            mDreamland
+        )
+        mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mRhcpSong3)
+        mMusicDao.addImages(mPinkFloydAlbumCover, mRhcpAlbumCover, mTheClashAlbumCover)
+
+        val doubleNestedMap = mMusicDao.getImageYearToArtistToAlbumsToSongsMapColumn()
+        val rhcpImageMap = doubleNestedMap.getValue(mRhcpAlbumCover.mImageYear)
+        val rhcpMap = rhcpImageMap.getValue(mRhcp)
+        val stadiumArcadiumList = rhcpMap.getValue("Stadium Arcadium")
+        val californicationList = rhcpMap.getValue("Californication")
+
+        val stadiumArcadiumExpectedList = listOf(mRhcpSong1, mRhcpSong2)
+        val californicationExpectedList = listOf(mRhcpSong3)
+
+        assertThat(doubleNestedMap.keys).containsExactlyElementsIn(
+            listOf(
+                mPinkFloydAlbumCover.mImageYear,
+                mRhcpAlbumCover.mImageYear,
+                mTheClashAlbumCover.mImageYear
+            )
+        )
+        assertThat(rhcpImageMap.keys).containsExactly(mRhcp)
+        assertThat(rhcpMap.keys).containsExactlyElementsIn(
+            listOf("Stadium Arcadium", "Californication")
+        )
+        assertThat(stadiumArcadiumList).containsExactlyElementsIn(stadiumArcadiumExpectedList)
+        assertThat(californicationList).containsExactlyElementsIn(californicationExpectedList)
+
+        // LEFT JOIN Checks
+        assertThat(doubleNestedMap).containsKey(mTheClashAlbumCover.mImageYear)
+        assertThat(doubleNestedMap[mTheClashAlbumCover.mImageYear]).isEmpty()
+        assertThat(doubleNestedMap).containsKey(mPinkFloydAlbumCover.mImageYear)
+        assertThat(doubleNestedMap[mPinkFloydAlbumCover.mImageYear]).containsKey(mPinkFloyd)
+        assertThat(doubleNestedMap[mPinkFloydAlbumCover.mImageYear]!![mPinkFloyd])
+            .containsKey(mTheDarkSideOfTheMoon.mAlbumName)
+        assertThat(
+            doubleNestedMap[mPinkFloydAlbumCover.mImageYear]
+            !![mPinkFloyd]
+            !![mTheDarkSideOfTheMoon.mAlbumName]
+        ).isEmpty()
+    }
+
     /**
      * Checks that the contents of the map are as expected.
      *
diff --git a/room/integration-tests/kotlintestapp/src/androidTestWithKspGenKotlin/java/androidx/room/integration/kotlintestapp/test/ValueClassConverterWrapperTest.kt b/room/integration-tests/kotlintestapp/src/androidTestWithKspGenKotlin/java/androidx/room/integration/kotlintestapp/test/ValueClassConverterWrapperTest.kt
index 14344bb..f735c1e 100644
--- a/room/integration-tests/kotlintestapp/src/androidTestWithKspGenKotlin/java/androidx/room/integration/kotlintestapp/test/ValueClassConverterWrapperTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTestWithKspGenKotlin/java/androidx/room/integration/kotlintestapp/test/ValueClassConverterWrapperTest.kt
@@ -214,7 +214,8 @@
         assertThrows<IllegalStateException> {
             db.dao().insertNullableEntity(data)
         }.hasMessageThat().isEqualTo(
-            "Cannot bind nullable value of inline class to a NOT NULL column."
+            "Cannot bind NULLABLE value 'data' of inline class 'NullableValue' to " +
+                "a NOT NULL column."
         )
     }
 
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/MusicDao.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/MusicDao.java
index 6f74a64..2b344fe 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/MusicDao.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/MusicDao.java
@@ -22,6 +22,7 @@
 import androidx.lifecycle.LiveData;
 import androidx.room.Dao;
 import androidx.room.Insert;
+import androidx.room.MapColumn;
 import androidx.room.MapInfo;
 import androidx.room.Query;
 import androidx.room.RawQuery;
@@ -46,14 +47,14 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSetMultimap;
 
+import io.reactivex.Flowable;
+
 import java.nio.ByteBuffer;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import io.reactivex.Flowable;
-
 @Dao
 @SuppressWarnings("ROOM_EXPAND_PROJECTION_WITH_UNUSED_COLUMNS")
 public interface MusicDao {
@@ -198,114 +199,142 @@
             getAllArtistAndTheirSongsAsLiveDataGuavaImmutableListMultimap();
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation")
     @MapInfo(keyColumn = "mArtistName")
     @Query("SELECT * FROM Artist JOIN Song ON Artist.mArtistName = Song.mArtist")
     Map<String, List<Song>> getArtistNameToSongs();
 
     @RewriteQueriesToDropUnusedColumns
+    @Query("SELECT * FROM Artist JOIN Song ON Artist.mArtistName = Song.mArtist")
+    Map<@MapColumn(columnName = "mArtistName") String,
+            List<@MapColumn(columnName = "mReleasedYear") Integer>> getArtistNameToSongsMapColumn();
+
+    @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mReleasedYear", valueColumn = "mReleasedYear")
     @Query("SELECT * FROM Album JOIN Song ON Song.mReleasedYear = Album.mAlbumReleaseYear")
     Map<Integer, List<Song>> getReleaseYearToAlbums();
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mImageYear")
     @Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
     LongSparseArray<Artist> getAllAlbumCoverYearToArtistsWithLongSparseArray();
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mImageYear")
     @Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
     SparseArrayCompat<Artist> getAllAlbumCoverYearToArtistsWithIntSparseArray();
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mReleasedYear", valueColumn = "mTitle")
     @Query("SELECT * FROM Album JOIN Song ON Song.mReleasedYear = Album.mAlbumReleaseYear")
     Map<Integer, List<String>> getReleaseYearToSongNames();
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mArtistName", valueColumn = "mArtist")
     @RawQuery
     Map<String, List<Song>> getArtistNameToSongsRawQuery(SupportSQLiteQuery query);
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mReleasedYear", valueColumn = "mReleasedYear")
     @RawQuery
     Map<Integer, List<Song>> getReleaseYearToAlbumsRawQuery(SupportSQLiteQuery query);
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mReleasedYear", valueColumn = "mTitle")
     @RawQuery
     Map<Integer, List<String>> getReleaseYearToSongNamesRawQuery(SupportSQLiteQuery query);
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(valueColumn = "songCount")
     @Query("SELECT *, COUNT(mSongId) as songCount FROM Artist JOIN Song ON Artist.mArtistName = "
             + "Song.mArtist GROUP BY mArtistName")
     Map<Artist, Integer> getArtistAndSongCountMap();
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(valueColumn = "songCount")
     @RawQuery
     Map<Artist, Integer> getArtistAndSongCountMapRawQuery(SupportSQLiteQuery query);
 
     // Other Map Key/Value Types
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(valueColumn = "mAlbumCover")
     @Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
     ImmutableMap<Artist, ByteBuffer> getAllArtistsWithAlbumCovers();
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(valueColumn = "mAlbumCover")
     @RawQuery
     ImmutableMap<Artist, ByteBuffer> getAllArtistsWithAlbumCoversRawQuery(SupportSQLiteQuery query);
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(valueColumn = "mImageYear")
     @Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
     ImmutableMap<Artist, Long> getAllArtistsWithAlbumCoverYear();
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(valueColumn = "mImageYear")
     @Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
     ArrayMap<Artist, Long> getAllArtistsWithAlbumCoverYearArrayMap();
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mImageYear")
     @RawQuery
     ImmutableMap<Long, Artist> getAllAlbumCoverYearToArtistsWithRawQuery(SupportSQLiteQuery query);
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mImageYear")
     @RawQuery
     ArrayMap<Long, Artist> getAllAlbumCoverYearToArtistsWithRawQueryArrayMap(
             SupportSQLiteQuery query
     );
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mAlbumCover", valueColumn = "mIsActive")
     @Query("SELECT * FROM Image JOIN Artist ON Artist.mArtistName = Image.mArtistInImage")
     ImmutableMap<ByteBuffer, Boolean> getAlbumCoversWithBandActivity();
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mAlbumCover", valueColumn = "mIsActive")
     @RawQuery
     ImmutableMap<ByteBuffer, Boolean> getAlbumCoversWithBandActivityRawQuery(
             SupportSQLiteQuery query
     );
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mDateReleased", valueColumn = "mIsActive")
     @Query("SELECT * FROM Image JOIN Artist ON Artist.mArtistName = Image.mArtistInImage")
     ImmutableMap<Date, Boolean> getAlbumDateWithBandActivity();
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mDateReleased", valueColumn = "mIsActive")
     @RawQuery
     ImmutableMap<Date, Boolean> getAlbumDateWithBandActivityRawQuery(SupportSQLiteQuery query);
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mFormat", valueColumn = "mIsActive")
     @Query("SELECT * FROM Image JOIN Artist ON Artist.mArtistName = Image.mArtistInImage")
     ImmutableMap<ImageFormat, Boolean> getImageFormatWithBandActivity();
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "mFormat", valueColumn = "mIsActive")
     @RawQuery
     ImmutableMap<ImageFormat, Boolean> getImageFormatWithBandActivityRawQuery(
             SupportSQLiteQuery query
     );
 
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(keyColumn = "dog", valueColumn = "cat")
     @RawQuery
     Map<Artist, Integer> getMapWithInvalidColumnRawQuery(SupportSQLiteQuery query);
@@ -320,6 +349,7 @@
     ImmutableListMultimap<Artist, Album> getArtistAndAlbumsLeftJoinGuava();
 
     @RewriteQueriesToDropUnusedColumns
+    @SuppressWarnings("deprecation") // for MapInfo
     @MapInfo(valueColumn = "mAlbumName")
     @Query("SELECT * FROM Artist LEFT JOIN Album ON Artist.mArtistName = Album.mAlbumArtist")
     Map<Artist, List<String>> getArtistAndAlbumNamesLeftJoin();
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/MultimapQueryTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/MultimapQueryTest.java
index d045d02..6fd554c 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/MultimapQueryTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/MultimapQueryTest.java
@@ -53,6 +53,8 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSetMultimap;
 
+import io.reactivex.Flowable;
+
 import org.hamcrest.MatcherAssert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -70,8 +72,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import io.reactivex.Flowable;
-
 /**
  * Tests multimap return type for JOIN statements.
  */
@@ -765,6 +765,18 @@
     }
 
     @Test
+    public void testStringToListOfSongsMapColumn() {
+        mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mPinkFloydSong1);
+        mMusicDao.addArtists(mRhcp, mAcDc, mTheClash, mPinkFloyd);
+
+        Map<String, List<Integer>> artistNameToSongsMap = mMusicDao.getArtistNameToSongsMapColumn();
+        assertThat(artistNameToSongsMap.containsKey("Pink Floyd")).isTrue();
+        assertThat(artistNameToSongsMap.get("Red Hot Chili Peppers")).containsExactlyElementsIn(
+                Arrays.asList(mRhcpSong1.mReleasedYear, mRhcpSong2.mReleasedYear)
+        );
+    }
+
+    @Test
     public void testIntegerToListOfAlbums() {
         mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mPinkFloydSong1);
         mMusicDao.addAlbums(
diff --git a/room/room-common/api/current.txt b/room/room-common/api/current.txt
index 95d009b..612c15f 100644
--- a/room/room-common/api/current.txt
+++ b/room/room-common/api/current.txt
@@ -263,15 +263,22 @@
     property public abstract kotlin.reflect.KClass<?> value;
   }
 
-  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface MapInfo {
-    method public abstract String keyColumn() default "";
-    method public abstract String keyTable() default "";
-    method public abstract String valueColumn() default "";
-    method public abstract String valueTable() default "";
-    property public abstract String keyColumn;
-    property public abstract String keyTable;
-    property public abstract String valueColumn;
-    property public abstract String valueTable;
+  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.TYPE) public @interface MapColumn {
+    method public abstract String columnName();
+    method public abstract String tableName() default "";
+    property public abstract String columnName;
+    property public abstract String tableName;
+  }
+
+  @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface MapInfo {
+    method @Deprecated public abstract String keyColumn() default "";
+    method @Deprecated public abstract String keyTable() default "";
+    method @Deprecated public abstract String valueColumn() default "";
+    method @Deprecated public abstract String valueTable() default "";
+    property @Deprecated public abstract String keyColumn;
+    property @Deprecated public abstract String keyTable;
+    property @Deprecated public abstract String valueColumn;
+    property @Deprecated public abstract String valueTable;
   }
 
   @IntDef({androidx.room.OnConflictStrategy.Companion.NONE, androidx.room.OnConflictStrategy.Companion.REPLACE, androidx.room.OnConflictStrategy.Companion.ROLLBACK, androidx.room.OnConflictStrategy.Companion.ABORT, androidx.room.OnConflictStrategy.Companion.FAIL, androidx.room.OnConflictStrategy.Companion.IGNORE}) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface OnConflictStrategy {
diff --git a/room/room-common/api/restricted_current.txt b/room/room-common/api/restricted_current.txt
index 85cc4ca..474272c 100644
--- a/room/room-common/api/restricted_current.txt
+++ b/room/room-common/api/restricted_current.txt
@@ -263,15 +263,22 @@
     property public abstract kotlin.reflect.KClass<?> value;
   }
 
-  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface MapInfo {
-    method public abstract String keyColumn() default "";
-    method public abstract String keyTable() default "";
-    method public abstract String valueColumn() default "";
-    method public abstract String valueTable() default "";
-    property public abstract String keyColumn;
-    property public abstract String keyTable;
-    property public abstract String valueColumn;
-    property public abstract String valueTable;
+  @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.TYPE) public @interface MapColumn {
+    method public abstract String columnName();
+    method public abstract String tableName() default "";
+    property public abstract String columnName;
+    property public abstract String tableName;
+  }
+
+  @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface MapInfo {
+    method @Deprecated public abstract String keyColumn() default "";
+    method @Deprecated public abstract String keyTable() default "";
+    method @Deprecated public abstract String valueColumn() default "";
+    method @Deprecated public abstract String valueTable() default "";
+    property @Deprecated public abstract String keyColumn;
+    property @Deprecated public abstract String keyTable;
+    property @Deprecated public abstract String valueColumn;
+    property @Deprecated public abstract String valueTable;
   }
 
   @IntDef({androidx.room.OnConflictStrategy.Companion.NONE, androidx.room.OnConflictStrategy.Companion.REPLACE, androidx.room.OnConflictStrategy.Companion.ROLLBACK, androidx.room.OnConflictStrategy.Companion.ABORT, androidx.room.OnConflictStrategy.Companion.FAIL, androidx.room.OnConflictStrategy.Companion.IGNORE}) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface OnConflictStrategy {
diff --git a/room/room-common/src/main/java/androidx/room/MapColumn.kt b/room/room-common/src/main/java/androidx/room/MapColumn.kt
new file mode 100644
index 0000000..423c6c4
--- /dev/null
+++ b/room/room-common/src/main/java/androidx/room/MapColumn.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2021 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.room
+
+/**
+ * Declares which column is used to build a map or multimap return value in a [Dao]
+ * query method.
+ *
+ * This annotation is required when the key or value of a Map (or nested map) is a single column of
+ * one of the built in types (primitives, boxed primitives, enum, String, byte[], ByteBuffer) or
+ * a type with a converter (e.g. Date, UUID, etc).
+ *
+ * The use of this annotation provides clarity on which column should be used in retrieving
+ * information required by the return type.
+ *
+ * Example:
+ *
+ * ```
+ *   @Query("SELECT * FROM Artist JOIN Song ON Artist.artistName = Song.artist")
+ *   fun getArtistNameToSongNames():
+ *   Map<@MapColumn(columnName = "artistName") String,
+ *   @MapColumn(columnName = "songName") List<String>>
+ *
+ *   @Query("SELECT *, COUNT(mSongId) as songCount FROM Artist JOIN Song ON
+ *   Artist.artistName = Song.artist GROUP BY artistName")
+ *   fun getArtistAndSongCounts(): Map<Artist, @MapColumn(columnName = "songCount") Integer>
+ * ```
+ *
+ * Column(s) specified in the provided @MapColumn annotation must be present in the query result.
+ */
+@Target(AnnotationTarget.TYPE)
+@Retention(AnnotationRetention.BINARY)
+public annotation class MapColumn(
+    /**
+     * The name of the column to be used for the map's key or value.
+     *
+     * @return The column name.
+     */
+    val columnName: String,
+
+    /**
+     * The name of the table or alias to be used for the map's column.
+     *
+     * Providing this value is optional. Useful for disambiguating between duplicate column names.
+     * For example, consider the following query:
+     * `SELECT * FROM Artist AS a JOIN Song AS s ON a.id == s.artistId`, then the `@MapColumn`
+     * for a return type `Map<String, List<Song>>` would be
+     * `Map<@MapColumn(columnName = "id", tableName = "a") String, List<Song>>`.
+     *
+     * @return The column table name.
+     */
+    val tableName: String = "",
+)
diff --git a/room/room-common/src/main/java/androidx/room/MapInfo.kt b/room/room-common/src/main/java/androidx/room/MapInfo.kt
index 526f949..93a0aeb 100644
--- a/room/room-common/src/main/java/androidx/room/MapInfo.kt
+++ b/room/room-common/src/main/java/androidx/room/MapInfo.kt
@@ -17,7 +17,7 @@
 package androidx.room
 
 /**
- * Declares which column(s) are used to build a map or multimap return value in a {@link Dao}
+ * Declares which column(s) are used to build a map or multimap return value in a [Dao]
  * query method.
  *
  * This annotation is required when the key or value of the Map is a single column of one of the
@@ -46,6 +46,7 @@
  */
 @Target(AnnotationTarget.FUNCTION)
 @Retention(AnnotationRetention.BINARY)
+@Deprecated("Use @MapColumn instead.")
 public annotation class MapInfo(
     /**
      * The name of the column to be used for the map's keys.
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
index ca01837..f72cec5 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
@@ -16,6 +16,7 @@
 
 package androidx.room.compiler.processing
 
+import androidx.room.compiler.codegen.XClassName
 import com.squareup.javapoet.ClassName
 import kotlin.reflect.KClass
 
@@ -39,6 +40,21 @@
     }
 
     /**
+     * Returns the list of [XAnnotation] elements that have the same qualified name as the given
+     * [annotationName]. Otherwise, returns an empty list.
+     *
+     * For repeated annotations declared in Java code, please use the repeated annotation type,
+     * not the container. Calling this method with a container annotation will have inconsistent
+     * behaviour between Java AP and KSP.
+     *
+     * @see [hasAnnotation]
+     * @see [hasAnnotationWithPackage]
+     */
+    fun getAnnotations(annotationName: XClassName): List<XAnnotation> {
+        return getAllAnnotations().filter { annotationName.canonicalName == it.qualifiedName }
+    }
+
+    /**
      * Gets the list of annotations with the given type.
      *
      * For repeated annotations declared in Java code, please use the repeated annotation type,
@@ -89,6 +105,16 @@
     }
 
     /**
+     * Returns `true` if this element is annotated with an [XAnnotation] that has the same
+     * qualified name as the given [annotationName].
+     *
+     * @see [hasAnyAnnotation]
+     */
+    fun hasAnnotation(annotationName: XClassName): Boolean {
+        return getAnnotations(annotationName).isNotEmpty()
+    }
+
+    /**
      * Returns `true` if this element has an annotation that is declared in the given package.
      * Alternatively, all annotations can be accessed with [getAllAnnotations].
      */
@@ -160,6 +186,18 @@
     }
 
     /**
+     * Returns the [XAnnotation] that has the same qualified name as [annotationName].
+     * Otherwise, `null` value is returned.
+     *
+     * @see [hasAnnotation]
+     * @see [getAnnotations]
+     * @see [hasAnnotationWithPackage]
+     */
+    fun getAnnotation(annotationName: XClassName): XAnnotation? {
+        return getAnnotations(annotationName).firstOrNull()
+    }
+
+    /**
      * Returns the [Annotation]s that are annotated with [annotationName]
      */
     fun getAnnotationsAnnotatedWith(
@@ -171,6 +209,17 @@
     }
 
     /**
+     * Returns the [Annotation]s that are annotated with [annotationName]
+     */
+    fun getAnnotationsAnnotatedWith(
+        annotationName: XClassName
+    ): Set<XAnnotation> {
+        return getAllAnnotations().filter {
+            it.type.typeElement?.hasAnnotation(annotationName) ?: false
+        }.toSet()
+    }
+
+    /**
      * Returns the [XAnnotation] that has the same qualified name as [annotationName].
      *
      * @see [hasAnnotation]
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt
index 0d041a0..e3e5a57 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt
@@ -83,6 +83,7 @@
     }
 
     override val kotlinMetadata: KmConstructorContainer? by lazy {
-        (enclosingElement as? JavacTypeElement)?.kotlinMetadata?.getConstructorMetadata(element)
+        (enclosingElement as? JavacTypeElement)?.kotlinMetadata
+            ?.getConstructorMetadata(element)
     }
 }
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt
index cdf34b6..356b357 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt
@@ -29,7 +29,7 @@
     abstract override val kotlinMetadata: KmFunctionContainer?
 
     override val jvmDescriptor by lazy {
-        element.descriptor()
+        element.descriptor(env.delegate)
     }
 
     abstract override val parameters: List<JavacMethodParameter>
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFieldElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFieldElement.kt
index ca1d5da..a0d9c1c 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFieldElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFieldElement.kt
@@ -28,6 +28,10 @@
     env: JavacProcessingEnv,
     element: VariableElement
 ) : JavacVariableElement(env, element), XFieldElement {
+
+    override val name: String
+        get() = (kotlinMetadata?.name ?: super.name)
+
     override fun getAllAnnotations(): List<XAnnotation> {
         return buildList {
             addAll(super.getAllAnnotations())
@@ -48,7 +52,7 @@
     }
 
     override val kotlinMetadata: KmPropertyContainer? by lazy {
-        (enclosingElement as? JavacTypeElement)?.kotlinMetadata?.getPropertyMetadata(name)
+        (enclosingElement as? JavacTypeElement)?.kotlinMetadata?.getPropertyMetadata(element)
     }
 
     private val syntheticMethodForAnnotations: JavacMethodElement? by lazy {
@@ -68,7 +72,7 @@
         get() = enclosingElement
 
     override val jvmDescriptor: String
-        get() = element.descriptor()
+        get() = element.descriptor(env.delegate)
 
     override val getter: XMethodElement? by lazy {
         kotlinMetadata?.getter?.let { getterMetadata ->
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
index 8c78886..66c3ea0 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
@@ -51,9 +51,14 @@
     override val kotlinMetadata by lazy { kotlinMetadataFactory() }
 
     override val name: String
-        get() = (kotlinMetadata?.name ?: super.name).sanitizeAsJavaParameterName(
-            argIndex = argIndex
-        )
+        get() = if (isReceiverParam() && enclosingElement.isAbstract()) {
+            // Receiver parameter names for abstract methods are not reliable across different
+            // versions of KAPT so we just build the name ourselves to match KSP.
+            // https://youtrack.jetbrains.com/issue/KT-18048/kapt-drops-method-parameter-names
+            "\$this\$${enclosingElement.name}"
+        } else {
+            (kotlinMetadata?.name ?: super.name)
+        }.sanitizeAsJavaParameterName(argIndex)
 
     override val kotlinType: KmTypeContainer?
         get() = kotlinMetadata?.type
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
index 5d3d6e4..3e30e02 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
@@ -108,6 +108,8 @@
                     element = it,
                 )
             }
+            // To be consistent with KSP consider delegates to not have a backing field.
+            .filterNot { it.kotlinMetadata?.isDelegated() == true }
     }
 
     private val allMethods = MemoizedSequence {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt
index 402ab9e..7695ee9 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt
@@ -19,9 +19,9 @@
 import com.squareup.javapoet.ArrayTypeName
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.TypeName
+import javax.annotation.processing.ProcessingEnvironment
 import javax.lang.model.element.Element
 import javax.lang.model.element.ExecutableElement
-import javax.lang.model.element.NestingKind
 import javax.lang.model.element.QualifiedNameable
 import javax.lang.model.element.TypeElement
 import javax.lang.model.element.VariableElement
@@ -45,16 +45,19 @@
  *
  * For reference, see the [JVM specification, section 4.3.2](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.2)
  */
-internal fun VariableElement.descriptor() = "$simpleName:${asType().descriptor()}"
+internal fun VariableElement.descriptor(env: ProcessingEnvironment) =
+    "$simpleName:${asType().descriptor(env)}"
 
 /**
  * Returns the method descriptor of this [ExecutableElement].
  *
  * For reference, see the [JVM specification, section 4.3.3](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3)
  */
-internal fun ExecutableElement.descriptor() = "$simpleName${asType().descriptor()}"
+internal fun ExecutableElement.descriptor(env: ProcessingEnvironment) =
+    "$simpleName${asType().descriptor(env)}"
 
-private fun TypeMirror.descriptor() = JvmDescriptorTypeVisitor.visit(this)
+private fun TypeMirror.descriptor(env: ProcessingEnvironment) =
+    JvmDescriptorTypeVisitor.visit(this, env)
 
 // see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.2-200
 internal fun String.typeNameFromJvmSignature(): TypeName {
@@ -110,13 +113,14 @@
  *
  * For reference, see the [JVM specification, section 4.3](http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3).
  */
-private object JvmDescriptorTypeVisitor : AbstractTypeVisitor8<String, Any?>() {
+private object JvmDescriptorTypeVisitor : AbstractTypeVisitor8<String, ProcessingEnvironment>() {
 
-    override fun visitNoType(t: NoType, u: Any?): String = "V"
+    override fun visitNoType(t: NoType, env: ProcessingEnvironment): String = "V"
 
-    override fun visitDeclared(t: DeclaredType, u: Any?): String = "L${t.asElement().internalName};"
+    override fun visitDeclared(t: DeclaredType, env: ProcessingEnvironment): String =
+        "L${t.asElement().internalName(env)};"
 
-    override fun visitPrimitive(t: PrimitiveType, u: Any?): String {
+    override fun visitPrimitive(t: PrimitiveType, env: ProcessingEnvironment): String {
         return when (t.kind) {
             TypeKind.BYTE -> "B"
             TypeKind.CHAR -> "C"
@@ -130,65 +134,46 @@
         }
     }
 
-    override fun visitArray(t: ArrayType, u: Any?): String = "[" + visit(t.componentType)
+    override fun visitArray(t: ArrayType, env: ProcessingEnvironment): String =
+        "[" + visit(t.componentType, env)
 
-    override fun visitWildcard(t: WildcardType, u: Any?): String = visitUnknown(t, u)
+    override fun visitWildcard(t: WildcardType, env: ProcessingEnvironment): String =
+        visitUnknown(t, env)
 
-    override fun visitExecutable(t: ExecutableType, u: Any?): String {
-        val parameterDescriptors = t.parameterTypes.joinToString("") { visit(it) }
-        val returnDescriptor = visit(t.returnType)
+    override fun visitExecutable(t: ExecutableType, env: ProcessingEnvironment): String {
+        val parameterDescriptors = t.parameterTypes.joinToString("") { visit(it, env) }
+        val returnDescriptor = visit(t.returnType, env)
         return "($parameterDescriptors)$returnDescriptor"
     }
 
-    override fun visitTypeVariable(t: TypeVariable, u: Any?): String = visit(t.upperBound)
+    override fun visitTypeVariable(t: TypeVariable, env: ProcessingEnvironment): String =
+        visit(t.upperBound, env)
 
-    override fun visitNull(t: NullType, u: Any?): String = visitUnknown(t, u)
+    override fun visitNull(t: NullType, env: ProcessingEnvironment): String = visitUnknown(t, env)
 
-    override fun visitError(t: ErrorType, u: Any?): String = visitDeclared(t, u)
+    override fun visitError(t: ErrorType, env: ProcessingEnvironment): String =
+        visitDeclared(t, env)
 
     // For a type variable with multiple bounds: "the erasure of a type variable is determined
     // by the first type in its bound" - JLS Sec 4.4
     // See https://docs.oracle.com/javase/specs/jls/se16/html/jls-4.html#jls-4.4
-    override fun visitIntersection(t: IntersectionType, u: Any?): String = visit(t.bounds[0])
+    override fun visitIntersection(t: IntersectionType, env: ProcessingEnvironment): String =
+        visit(t.bounds[0], env)
 
-    override fun visitUnion(t: UnionType, u: Any?): String = visitUnknown(t, u)
+    override fun visitUnion(t: UnionType, env: ProcessingEnvironment): String = visitUnknown(t, env)
 
-    override fun visitUnknown(t: TypeMirror, u: Any?): String = error("Unsupported type $t")
+    override fun visitUnknown(t: TypeMirror, env: ProcessingEnvironment): String =
+        error("Unsupported type $t")
 
     /**
      * Returns the name of this [TypeElement] in its "internal form".
      *
      * For reference, see the [JVM specification, section 4.2](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.2).
      */
-    private val Element.internalName: String
-        get() = when (this) {
-            is TypeElement ->
-                when (nestingKind) {
-                    NestingKind.TOP_LEVEL ->
-                        qualifiedName.toString().replace('.', '/')
-                    NestingKind.MEMBER, NestingKind.LOCAL ->
-                        enclosingElement.internalName + "$" + simpleName
-                    NestingKind.ANONYMOUS ->
-                        elementError("Unsupported nesting $nestingKind", this)
-                    else ->
-                        elementError("Unsupported, nestingKind == null", this)
-                }
-            is ExecutableElement -> enclosingElement.internalName
-            is QualifiedNameable -> qualifiedName.toString().replace('.', '/')
-            else -> simpleName.toString()
-        }
-
-    /**
-     * Throws an exception with the error [msg] and the [element] and its enclosing elements appended.
-     */
-    private fun elementError(msg: String, element: Element): Nothing {
-        fun buildName(element: Element): String {
-            val enclosingPart =
-                element.enclosingElement?.let { buildName(it) + "." } ?: ""
-            val simpleName = element.simpleName.ifEmpty { "<unnamed>" }
-            return enclosingPart + simpleName
-        }
-        val name = buildName(element)
-        error("$msg - On element $name")
+    private fun Element.internalName(env: ProcessingEnvironment): String = when (this) {
+        is TypeElement -> env.elementUtils.getBinaryName(this).toString().replace('.', '/')
+        is ExecutableElement -> enclosingElement.internalName(env)
+        is QualifiedNameable -> qualifiedName.toString().replace('.', '/')
+        else -> simpleName.toString()
     }
 }
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
index 7d93ec0..8c9d94b 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
@@ -27,6 +27,7 @@
 import javax.lang.model.element.Element
 import javax.lang.model.element.ElementKind
 import javax.lang.model.element.ExecutableElement
+import javax.lang.model.element.VariableElement
 import javax.tools.Diagnostic
 import kotlinx.metadata.Flag
 import kotlinx.metadata.Flags
@@ -42,6 +43,7 @@
 import kotlinx.metadata.KmValueParameter
 import kotlinx.metadata.jvm.KotlinClassMetadata
 import kotlinx.metadata.jvm.annotations
+import kotlinx.metadata.jvm.fieldSignature
 import kotlinx.metadata.jvm.getterSignature
 import kotlinx.metadata.jvm.setterSignature
 import kotlinx.metadata.jvm.signature
@@ -52,6 +54,7 @@
 }
 
 internal class KmClassContainer(
+    private val env: JavacProcessingEnv,
     private val kmClass: KmClass
 ) : KmFlags {
     override val flags: Flags
@@ -116,7 +119,7 @@
         check(method.kind == ElementKind.METHOD) {
             "must pass an element type of method"
         }
-        return functionByDescriptor[method.descriptor()]
+        return functionByDescriptor[method.descriptor(env.delegate)]
     }
 
     private val functionByDescriptor: Map<String, KmFunctionContainer> by lazy {
@@ -136,12 +139,17 @@
         check(method.kind == ElementKind.CONSTRUCTOR) {
             "must pass an element type of constructor"
         }
-        val methodSignature = method.descriptor()
+        val methodSignature = method.descriptor(env.delegate)
         return constructorList.firstOrNull { it.descriptor == methodSignature }
     }
 
-    fun getPropertyMetadata(propertyName: String): KmPropertyContainer? =
-        propertyList.firstOrNull { it.name == propertyName }
+    fun getPropertyMetadata(field: VariableElement): KmPropertyContainer? {
+        check(field.kind == ElementKind.FIELD) {
+            "must pass an element type of field"
+        }
+        val fieldName = field.simpleName.toString()
+        return propertyList.firstOrNull { it.backingFieldName == fieldName || it.name == fieldName }
+    }
 
     companion object {
         /**
@@ -162,7 +170,7 @@
                 )
             }
             return when (classMetadata) {
-                is KotlinClassMetadata.Class -> KmClassContainer(classMetadata.toKmClass())
+                is KotlinClassMetadata.Class -> KmClassContainer(env, classMetadata.toKmClass())
                 // Synthetic classes generated for various Kotlin features ($DefaultImpls,
                 // $WhenMappings, etc) are ignored because the data contained does not affect
                 // the metadata derived APIs. These classes are never referenced by user code but
@@ -268,6 +276,7 @@
 internal class KmPropertyContainer(
     private val kmProperty: KmProperty,
     val type: KmTypeContainer,
+    val backingFieldName: String?,
     val getter: KmFunctionContainer?,
     val setter: KmFunctionContainer?,
     val syntheticMethodForAnnotations: KmFunctionContainer?,
@@ -279,6 +288,7 @@
     val typeParameters: List<KmTypeContainer>
         get() = type.typeArguments
     fun isNullable() = type.isNullable()
+    fun isDelegated() = Flag.Property.IS_DELEGATED(flags)
 }
 
 internal class KmTypeContainer(
@@ -408,6 +418,7 @@
     KmPropertyContainer(
         kmProperty = this,
         type = this.returnType.asContainer(),
+        backingFieldName = fieldSignature?.name,
         getter = getterSignature?.let {
             KmPropertyFunctionContainerImpl(
                 flags = this.getterFlags,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index 354ee85..44bb15d 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -174,7 +174,7 @@
 
     private val _declaredFields by lazy {
         _declaredProperties.filter {
-            it.declaration.hasBackingFieldFixed
+            it.declaration.hasBackingField
         }
     }
 
@@ -410,13 +410,6 @@
         }
     }
 
-    /**
-     * Workaround for https://github.com/google/ksp/issues/529 where KSP returns false for
-     * backing field when the property has a lateinit modifier.
-     */
-    private val KSPropertyDeclaration.hasBackingFieldFixed
-        get() = hasBackingField || modifiers.contains(Modifier.LATEINIT)
-
     @OptIn(KspExperimental::class)
     fun KSDeclarationContainer?.getDeclarationsInSourceOrder() = this?.let {
         env.resolver.getDeclarationsInSourceOrder(it)
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
index db2aa22..181265e6 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
@@ -1429,4 +1429,52 @@
                 )
         }
     }
+
+    @Test
+    fun receiverParameterNames(@TestParameter isPrecompiled: Boolean) {
+        val kotlinSource = Source.kotlin(
+            "foo.bar.Subject.kt",
+            """
+            package foo.bar
+            abstract class Subject {
+                fun Bar.method(): Unit = TODO()
+                fun Bar.methodWithParam(name: String): Unit = TODO()
+                abstract fun Bar.abstractMethod()
+                abstract fun Bar.abstractMethodWithParam(name: String)
+                @JvmName("newMethodWithJvmName")
+                fun Bar.methodWithJvmName(): Unit = TODO()
+                @JvmName("newMethodWithJvmNameAndParam")
+                fun Bar.methodWithJvmNameAndParam(name: String): Unit = TODO()
+            }
+            class Bar
+            """.trimIndent())
+        runProcessorTest(
+            sources = if (isPrecompiled) {
+                emptyList()
+            } else {
+                listOf(kotlinSource)
+            },
+            classpath = if (isPrecompiled) {
+                compileFiles(listOf(kotlinSource))
+            } else {
+                emptyList()
+            }
+        ) { invocation ->
+            val subject = invocation.processingEnv.requireTypeElement("foo.bar.Subject")
+
+            // Assert on the method and parameter names of each declared method.
+            assertThat(
+                subject.getDeclaredMethods().map { method ->
+                    "${method.name}(${method.parameters.joinToString(", ") { it.name }})"
+                }
+            ).containsExactly(
+                "method(\$this\$method)",
+                "methodWithParam(\$this\$methodWithParam, name)",
+                "abstractMethod(\$this\$abstractMethod)",
+                "abstractMethodWithParam(\$this\$abstractMethodWithParam, name)",
+                "methodWithJvmName(\$this\$methodWithJvmName)",
+                "methodWithJvmNameAndParam(\$this\$methodWithJvmNameAndParam, name)",
+            ).inOrder()
+        }
+    }
 }
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
index 0d3d952..5b165ae 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
@@ -29,6 +29,7 @@
 import androidx.room.compiler.processing.util.compileFiles
 import androidx.room.compiler.processing.util.getAllFieldNames
 import androidx.room.compiler.processing.util.getDeclaredField
+import androidx.room.compiler.processing.util.getDeclaredMethodByJvmName
 import androidx.room.compiler.processing.util.getField
 import androidx.room.compiler.processing.util.getMethodByJvmName
 import androidx.room.compiler.processing.util.runProcessorTest
@@ -822,6 +823,26 @@
     }
 
     @Test
+    fun lazyProperty() {
+        val src = Source.kotlin(
+            "Subject.kt",
+            """
+            class Subject {
+              val myLazy by lazy { "wow" }
+            }
+            """.trimIndent()
+        )
+        runTest(sources = listOf(src)) {
+            val subject = it.processingEnv.requireTypeElement("Subject")
+            val fields = subject.getDeclaredFields()
+            assertThat(fields).isEmpty()
+            val method = subject.getDeclaredMethodByJvmName("getMyLazy")
+            assertThat(method).isNotNull()
+            assertThat(method.isKotlinPropertyMethod()).isTrue()
+        }
+    }
+
+    @Test
     fun declaredAndInstanceMethods() {
         val src = Source.kotlin(
             "Foo.kt",
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt
index 86d3822..90f1bac 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt
@@ -425,9 +425,9 @@
                         roundEnv.getElementsAnnotatedWith(annotations.first()).map { element ->
                             when (element.kind) {
                                 FIELD ->
-                                    MoreElements.asVariable(element).descriptor()
+                                    MoreElements.asVariable(element).descriptor(processingEnv)
                                 METHOD, CONSTRUCTOR ->
-                                    MoreElements.asExecutable(element).descriptor()
+                                    MoreElements.asExecutable(element).descriptor(processingEnv)
                                 else -> error("Unsupported element to describe.")
                             }
                         }.toSet().let(handler)
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt
index eb676b6..26b9bab 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt
@@ -19,7 +19,6 @@
 import androidx.kruth.assertThat
 import androidx.kruth.assertWithMessage
 import androidx.room.compiler.processing.XNullability
-import androidx.room.compiler.processing.XProcessingEnvConfig
 import androidx.room.compiler.processing.javac.JavacProcessingEnv
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
@@ -27,7 +26,6 @@
 import androidx.room.compiler.processing.util.runJavaProcessorTest
 import androidx.room.compiler.processing.util.runKaptTest
 import androidx.room.compiler.processing.util.sanitizeAsJavaParameterName
-import javax.annotation.processing.ProcessingEnvironment
 import javax.lang.model.element.ExecutableElement
 import javax.lang.model.element.TypeElement
 import javax.lang.model.util.ElementFilter
@@ -55,9 +53,9 @@
             }
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { processingEnv ->
+        simpleRun(listOf(src)) { env ->
             val (testClassElement, metadataElement) = getMetadataElement(
-                processingEnv,
+                env,
                 "Subject"
             )
             val constructors = testClassElement.getConstructors()
@@ -109,9 +107,9 @@
             }
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { processingEnv ->
+        simpleRun(listOf(src)) { env ->
             val (testClassElement, metadataElement) = getMetadataElement(
-                processingEnv,
+                env,
                 "Subject"
             )
             testClassElement.getDeclaredMethod("functionWithParams")
@@ -157,14 +155,14 @@
             }
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
+        simpleRun(listOf(src)) { env ->
             val (testClassElement, metadataElement) = getMetadataElement(
-                invocation,
+                env,
                 "Subject"
             )
             assertThat(
                 testClassElement.getConstructors().map {
-                    val desc = it.descriptor()
+                    val desc = it.descriptor(env.delegate)
                     desc to (desc == metadataElement.primaryConstructorSignature)
                 }
             ).containsExactly(
@@ -191,14 +189,15 @@
             }
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
+        simpleRun(listOf(src)) { env ->
             val (testClassElement, metadataElement) = getMetadataElement(
-                invocation,
+                env,
                 "Subject"
             )
             assertThat(
                 testClassElement.getDeclaredMethods().map {
-                    it.simpleName.toString() to metadataElement.getFunctionMetadata(it)?.isSuspend()
+                    it.simpleName.toString() to metadataElement.getFunctionMetadata(it)
+                        ?.isSuspend()
                 }
             ).containsExactly(
                 "emptyFunction" to false,
@@ -220,12 +219,12 @@
             object AnObject
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
-            val (_, objectTypeMetadata) = getMetadataElement(invocation, "AnObject")
+        simpleRun(listOf(src)) { env ->
+            val (_, objectTypeMetadata) = getMetadataElement(env, "AnObject")
             assertThat(objectTypeMetadata.isObject()).isTrue()
-            val (_, classTypeMetadata) = getMetadataElement(invocation, "KotlinClass")
+            val (_, classTypeMetadata) = getMetadataElement(env, "KotlinClass")
             assertThat(classTypeMetadata.isObject()).isFalse()
-            val (_, interfaceMetadata) = getMetadataElement(invocation, "KotlinInterface")
+            val (_, interfaceMetadata) = getMetadataElement(env, "KotlinInterface")
             assertThat(interfaceMetadata.isObject()).isFalse()
         }
     }
@@ -241,9 +240,9 @@
             }
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
+        simpleRun(listOf(src)) { env ->
             val (testDaoElement, testDaoMetadata) = getMetadataElement(
-                invocation,
+                env,
                 "Subject"
             )
             val nonNullListMethod = testDaoElement.getDeclaredMethod("nonNullList")
@@ -273,38 +272,48 @@
             }
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
-            val (_, testMetadata) = getMetadataElement(
-                invocation,
+        simpleRun(listOf(src)) { env ->
+            val (typeElement, testMetadata) = getMetadataElement(
+                env,
                 "Properties"
             )
-            testMetadata.getPropertyMetadata("nonNull").let { property ->
+            testMetadata.getPropertyMetadata(
+                typeElement.getDeclaredField("nonNull")
+            ).let { property ->
                 assertThat(property?.name).isEqualTo("nonNull")
                 assertThat(property?.typeParameters).isEmpty()
                 assertThat(property?.isNullable()).isFalse()
             }
 
-            testMetadata.getPropertyMetadata("nullable").let { property ->
+            testMetadata.getPropertyMetadata(
+                typeElement.getDeclaredField("nullable")
+            ).let { property ->
                 assertThat(property?.name).isEqualTo("nullable")
                 assertThat(property?.typeParameters).isEmpty()
                 assertThat(property?.isNullable()).isTrue()
             }
 
-            testMetadata.getPropertyMetadata("nullableTypeArgument").let { property ->
+            testMetadata.getPropertyMetadata(
+                typeElement.getDeclaredField("nullableTypeArgument")
+            ).let { property ->
                 assertThat(property?.name).isEqualTo("nullableTypeArgument")
                 assertThat(property?.isNullable()).isFalse()
                 assertThat(property?.typeParameters).hasSize(1)
                 assertThat(property?.typeParameters?.single()?.isNullable()).isTrue()
             }
 
-            testMetadata.getPropertyMetadata("nonNullTypeArgument").let { property ->
+            testMetadata.getPropertyMetadata(
+                typeElement.getDeclaredField("nonNullTypeArgument")
+            ).let { property ->
                 assertThat(property?.name).isEqualTo("nonNullTypeArgument")
                 assertThat(property?.isNullable()).isFalse()
                 assertThat(property?.typeParameters).hasSize(1)
                 assertThat(property?.typeParameters?.single()?.isNullable()).isFalse()
             }
 
-            testMetadata.getPropertyMetadata("multipleTypeArguments").let { property ->
+            testMetadata.getPropertyMetadata(
+                typeElement.getDeclaredField("multipleTypeArguments")
+            ).let { property ->
                 assertThat(property?.name).isEqualTo("multipleTypeArguments")
                 assertThat(property?.isNullable()).isFalse()
                 assertThat(property?.typeParameters).hasSize(2)
@@ -341,9 +350,9 @@
             }
         """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
+        simpleRun(listOf(src)) { env ->
             val (element, metadata) = getMetadataElement(
-                invocation,
+                env,
                 "Subject"
             )
 
@@ -485,7 +494,9 @@
             // tests value class properties. They won't show up in KAPT stubs since they don't have
             // valid java source names but we still validate them here for consistency. Maybe one
             // day we'll change Javac element to include these if we support Kotlin codegen in KAPT
-            metadata.getPropertyMetadata("valueProp").let { valueProp ->
+            metadata.getPropertyMetadata(
+                element.getDeclaredField("valueProp")
+            ).let { valueProp ->
                 assertGetter(
                     kmFunction = valueProp?.getter,
                     name = "getValueProp",
@@ -499,7 +510,9 @@
                     paramNullable = true
                 )
             }
-            metadata.getPropertyMetadata("internalValueProp").let { valueProp ->
+            metadata.getPropertyMetadata(
+                element.getDeclaredField("internalValueProp")
+            ).let { valueProp ->
                 assertGetter(
                     kmFunction = valueProp?.getter,
                     name = "getInternalValueProp",
@@ -529,9 +542,9 @@
             }
         """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
+        simpleRun(listOf(src)) { env ->
             val (element, metadata) = getMetadataElement(
-                invocation,
+                env,
                 "Subject"
             )
             metadata.getFunctionMetadata(
@@ -578,9 +591,9 @@
             }
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
+        simpleRun(listOf(src)) { env ->
             val (testDaoElement, testDaoMetadata) = getMetadataElement(
-                invocation,
+                env,
                 "Subject"
             )
             fun assertParams(params: List<KmValueParameterContainer>?) {
@@ -617,17 +630,17 @@
         val src = Source.kotlin(
             "Subject.kt",
             """
-            interface Subject {
-                val nullableArrayWithNonNullComponent : Array<Int>?
-                val nullableArrayWithNullableComponent : Array<Int?>?
-                val nonNullArrayWithNonNullComponent : Array<Int>
-                val nonNullArrayWithNullableComponent : Array<Int?>
+            class Subject {
+                val nullableArrayWithNonNullComponent : Array<Int>? = TODO()
+                val nullableArrayWithNullableComponent : Array<Int?>? = TODO()
+                val nonNullArrayWithNonNullComponent : Array<Int> = TODO()
+                val nonNullArrayWithNullableComponent : Array<Int?> = TODO()
             }
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
-            val (_, metadata) = getMetadataElement(
-                invocation,
+        simpleRun(listOf(src)) { env ->
+            val (typeElement, metadata) = getMetadataElement(
+                env,
                 "Subject"
             )
             val propertyNames = listOf(
@@ -638,7 +651,7 @@
             )
             assertThat(
                 propertyNames
-                    .mapNotNull(metadata::getPropertyMetadata)
+                    .mapNotNull { metadata.getPropertyMetadata(typeElement.getDeclaredField(it)) }
                     .map {
                         Triple(it.name, it.isNullable(), it.typeParameters.single().isNullable())
                     }
@@ -669,18 +682,18 @@
             abstract class WithSuperType : Map<String, Int?> {}
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
-            val (_, simple) = getMetadataElement(invocation, "Simple")
+        simpleRun(listOf(src)) { env ->
+            val (_, simple) = getMetadataElement(env, "Simple")
             assertThat(simple.type.isNullable()).isFalse()
             assertThat(simple.type.typeArguments).isEmpty()
 
-            val (_, twoArgGeneric) = getMetadataElement(invocation, "TwoArgGeneric")
+            val (_, twoArgGeneric) = getMetadataElement(env, "TwoArgGeneric")
             assertThat(twoArgGeneric.type.isNullable()).isFalse()
             assertThat(twoArgGeneric.type.typeArguments).hasSize(2)
             assertThat(twoArgGeneric.type.typeArguments[0].isNullable()).isFalse()
             assertThat(twoArgGeneric.type.typeArguments[1].isNullable()).isFalse()
 
-            val (_, withUpperBounds) = getMetadataElement(invocation, "WithUpperBounds")
+            val (_, withUpperBounds) = getMetadataElement(env, "WithUpperBounds")
             assertThat(withUpperBounds.type.typeArguments).hasSize(2)
             assertThat(withUpperBounds.type.typeArguments[0].upperBounds).hasSize(1)
             assertThat(withUpperBounds.type.typeArguments[0].upperBounds!![0].isNullable())
@@ -689,7 +702,7 @@
             assertThat(withUpperBounds.type.typeArguments[1].upperBounds!![0].isNullable())
                 .isTrue()
 
-            val (_, withSuperType) = getMetadataElement(invocation, "WithSuperType")
+            val (_, withSuperType) = getMetadataElement(env, "WithSuperType")
             assertThat(withSuperType.superType?.typeArguments?.get(0)?.isNullable()).isFalse()
             assertThat(withSuperType.superType?.typeArguments?.get(1)?.isNullable()).isTrue()
         }
@@ -707,17 +720,23 @@
             }
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
-            val (_, subject) = getMetadataElement(invocation, "Subject")
-            subject.getPropertyMetadata("simple")!!.type.erasure().let {
+        simpleRun(listOf(src)) { env ->
+            val (typeElement, subject) = getMetadataElement(env, "Subject")
+            subject.getPropertyMetadata(
+                typeElement.getDeclaredField("simple")
+            )!!.type.erasure().let {
                 assertThat(it.isNullable()).isFalse()
                 assertThat(it.typeArguments).isEmpty()
             }
-            subject.getPropertyMetadata("nullableGeneric")!!.type.erasure().let {
+            subject.getPropertyMetadata(
+                typeElement.getDeclaredField("nullableGeneric")
+            )!!.type.erasure().let {
                 assertThat(it.isNullable()).isTrue()
                 assertThat(it.typeArguments).isEmpty()
             }
-            subject.getPropertyMetadata("nonNullGeneric")!!.type.erasure().let {
+            subject.getPropertyMetadata(
+                typeElement.getDeclaredField("nonNullGeneric")
+            )!!.type.erasure().let {
                 assertThat(it.isNullable()).isFalse()
                 assertThat(it.typeArguments).isEmpty()
             }
@@ -749,7 +768,7 @@
         ) { invocation ->
             val (_, metadata) =
                 getMetadataElement(
-                    (invocation.processingEnv as JavacProcessingEnv).delegate,
+                    invocation.processingEnv as JavacProcessingEnv,
                     "KotlinClass"
                 )
             assertThat(metadata).isNotNull()
@@ -779,8 +798,8 @@
             abstract class C
             """.trimIndent()
         )
-        simpleRun(listOf(src)) { invocation ->
-            val (subjectElement, subjectMetadata) = getMetadataElement(invocation, "Subject")
+        simpleRun(listOf(src)) { env ->
+            val (subjectElement, subjectMetadata) = getMetadataElement(env, "Subject")
             fun assertKmFunctionFound(functionName: String) {
                 val kmFunction = subjectMetadata.getFunctionMetadata(
                     subjectElement.getDeclaredMethod(functionName)
@@ -794,6 +813,59 @@
     }
 
     @Test
+    fun properties_anonymousNestingKind() {
+        // Only private functions are relevant to the test since public (or internal) properties
+        // are required to declare their type explicitly when right-hand side is ambiguous.
+        // b/232742201
+        val src = Source.kotlin(
+            "Subject.kt",
+            """
+            class Subject {
+                private val lazyA by lazy {
+                    object: A { }
+                }
+                private val lazyAB by lazy {
+                    object: A, B { }
+                }
+                private val lazyABC by lazy {
+                    object: C(), A, B { }
+                }
+                private val lazyC by lazy {
+                    object: C() { }
+                }
+                private val lazyAC by lazy {
+                    object: C(), A { }
+                }
+                private val lazyAB_declaredA: A by lazy {
+                    object: A, B { }
+                }
+                private val lazyAB_declaredB: B by lazy {
+                    object: A, B { }
+                }
+                private val lazyABC_declaredC: C by lazy {
+                    object: C(), A { }
+                }
+            }
+
+            interface A
+            interface B
+            abstract class C
+            """.trimIndent()
+        )
+        simpleRun(
+            sources = listOf(src)
+        ) { env ->
+            val subject = env.requireTypeElement("Subject")
+            subject.getDeclaredFields().forEach {
+                assertThat(it.getter).isNotNull()
+            }
+            subject.getDeclaredMethods().forEach {
+                assertThat(it.isKotlinPropertyMethod()).isTrue()
+            }
+        }
+    }
+
+    @Test
     fun ignore_syntheticMetadata_defaultImpls() {
         val src = Source.kotlin(
             "Subject.kt",
@@ -806,8 +878,8 @@
         simpleRun(
             sources = listOf(src),
             kotlincArgs = listOf("-Xjvm-default=disable")
-        ) {
-            val subjectElement = processingEnv.requireTypeElement("Subject.DefaultImpls")
+        ) { env ->
+            val subjectElement = env.requireTypeElement("Subject.DefaultImpls")
             // Call metadata derived API causing it to be read
             assertThat(subjectElement.isKotlinObject()).isFalse()
             assertCompilationResult {
@@ -840,9 +912,9 @@
         )
         simpleRun(
             sources = listOf(src),
-        ) {
-            assertThat(processingEnv.findTypeElement("Subject.Fruit")).isNotNull()
-            val subjectElement = processingEnv.findTypeElement("Subject.WhenMappings")
+        ) { env ->
+            assertThat(env.findTypeElement("Subject.Fruit")).isNotNull()
+            val subjectElement = env.findTypeElement("Subject.WhenMappings")
                 // Currently $WhenMapping has the ACC_SYNTHETIC flag making it unreadable by
                 // annotation processors making it impossible to verify synthetic metadata is
                 // ignored.
@@ -877,19 +949,19 @@
         )
         simpleRun(
             sources = listOf(aSrc, bSrc),
-        ) {
+        ) { env ->
             // Find the multi file class facade element
-            val facadeElement = processingEnv.requireTypeElement("Subject")
+            val facadeElement = env.requireTypeElement("Subject")
             // Call metadata derived API causing it to be read
             assertThat(facadeElement.isKotlinObject()).isFalse()
 
             // Try to find the multi file class part elements, currently these classes have the
             // ACC_SYNTHETIC flag making them unreadable by annotation processors and impossible to
             // verify that multi file metadata is ignored.
-            val facadePartOne = processingEnv.findTypeElement("Subject__AKt")
+            val facadePartOne = env.findTypeElement("Subject__AKt")
                 ?: throw AssumptionViolatedException("No test if MultiFileClassPart is not found")
             assertThat(facadePartOne.isKotlinObject()).isFalse()
-            val facadePartTwo = processingEnv.findTypeElement("Subject__BKt")
+            val facadePartTwo = env.findTypeElement("Subject__BKt")
                 ?: throw AssumptionViolatedException("No test if MultiFileClassPart is not found")
             assertThat(facadePartTwo.isKotlinObject()).isFalse()
             assertCompilationResult {
@@ -904,13 +976,16 @@
         it.simpleName.toString() == name
     }
 
+    private fun TypeElement.getDeclaredField(name: String) =
+        ElementFilter.fieldsIn(enclosedElements).first { it.simpleName.toString() == name }
+
     private fun TypeElement.getConstructors() = ElementFilter.constructorsIn(enclosedElements)
 
     @Suppress("NAME_SHADOWING") // intentional
     private fun simpleRun(
         sources: List<Source> = emptyList(),
         kotlincArgs: List<String> = emptyList(),
-        handler: XTestInvocation.(ProcessingEnvironment) -> Unit
+        handler: XTestInvocation.(JavacProcessingEnv) -> Unit
     ) {
         val (sources, classpath) = if (preCompiled) {
             emptyList<Source>() to compileFiles(sources)
@@ -922,18 +997,17 @@
             classpath = classpath,
             kotlincArguments = kotlincArgs
         ) {
-            val processingEnv = it.processingEnv
-            if (processingEnv !is JavacProcessingEnv) {
+            val env = it.processingEnv
+            if (env !is JavacProcessingEnv) {
                 throw AssumptionViolatedException("This test only works for java/kapt compilation")
             }
-            it.handler(processingEnv.delegate)
+            it.handler(env)
         }
     }
 
-    private fun getMetadataElement(processingEnv: ProcessingEnvironment, qName: String) =
-        processingEnv.elementUtils.getTypeElement(qName).let {
-            it to KmClassContainer.createFor(
-                JavacProcessingEnv(processingEnv, XProcessingEnvConfig.DEFAULT), it)!!
+    private fun getMetadataElement(env: JavacProcessingEnv, qName: String) =
+        env.elementUtils.getTypeElement(qName).let {
+            it to KmClassContainer.createFor(env, it)!!
         }
 
     companion object {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 86990ae..425bf1c 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -64,6 +64,8 @@
     val CANNOT_USE_UNBOUND_GENERICS_IN_DAO_CLASSES = "Cannot use unbound generics in Dao classes." +
         " If you are trying to create a base DAO, create a normal class, extend it with type" +
         " params then mark the subclass with @Dao."
+    val CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY = "Cannot use @MapColumn and " +
+        " @MapInfo annotation in the same function. Please prefer using @MapColumn only."
     val CANNOT_FIND_GETTER_FOR_FIELD = "Cannot find getter for field."
     val CANNOT_FIND_SETTER_FOR_FIELD = "Cannot find setter for field."
     val MISSING_PRIMARY_KEY = "An entity must have at least 1 field annotated with @PrimaryKey"
@@ -152,24 +154,18 @@
     val DELETION_MISSING_PARAMS = "Method annotated with" +
         " @Delete but does not have any parameters to delete."
 
-    fun cannotMapInfoSpecifiedColumn(column: String, columnsInQuery: List<String>) =
-        "Column specified in the provided @MapInfo annotation must be present in the query. " +
+    fun cannotMapSpecifiedColumn(column: String, columnsInQuery: List<String>, annotation: String) =
+        "Column specified in the provided @$annotation annotation must be present in the query. " +
             "Provided: $column. Columns found: ${columnsInQuery.joinToString(", ")}"
 
     val MAP_INFO_MUST_HAVE_AT_LEAST_ONE_COLUMN_PROVIDED = "To use the @MapInfo annotation, you " +
         "must provide either the key column name, value column name, or both."
 
-    fun keyMayNeedMapInfo(keyArg: String): String {
+    fun mayNeedMapColumn(columnArg: String): String {
         return """
-            Looks like you may need to use @MapInfo to clarify the 'keyColumn' needed for
-            the return type of a method. Type argument that needs @MapInfo: $keyArg
-            """.trim()
-    }
-
-    fun valueMayNeedMapInfo(valueArg: String): String {
-        return """
-            Looks like you may need to use @MapInfo to clarify the 'valueColumn' needed for
-            the return type of a method. Type argument that needs @MapInfo: $valueArg
+            Looks like you may need to use @MapColumn to clarify the 'columnName' needed for
+            type argument(s) in the return type of a method. Type argument that needs
+            @MapColumn: $columnArg
             """.trim()
     }
 
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
index d9333f1..50be0d2 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
@@ -26,7 +26,7 @@
 import androidx.room.parser.ParsedQuery
 import androidx.room.parser.QueryType
 import androidx.room.parser.SqlParser
-import androidx.room.processor.ProcessorErrors.cannotMapInfoSpecifiedColumn
+import androidx.room.processor.ProcessorErrors.cannotMapSpecifiedColumn
 import androidx.room.solver.TypeAdapterExtras
 import androidx.room.solver.query.result.PojoRowAdapter
 import androidx.room.verifier.ColumnInfo
@@ -208,6 +208,7 @@
         )
     }
 
+    @Suppress("DEPRECATION") // Due to MapInfo usage
     private fun getQueryMethod(
         delegate: MethodProcessorDelegate,
         returnType: XType,
@@ -284,6 +285,7 @@
      * Parse @MapInfo annotation, validate its inputs and put information in the bag of extras,
      * it will be later used by the TypeAdapterStore.
      */
+    @Suppress("DEPRECATION") // Due to @MapInfo usage
     private fun processMapInfo(
         mapInfoAnnotation: XAnnotationBox<androidx.room.MapInfo>,
         query: ParsedQuery,
@@ -323,18 +325,20 @@
                 keyColumn.isEmpty() || resultColumns.contains(keyColumn, keyTable),
                 queryExecutableElement
             ) {
-                cannotMapInfoSpecifiedColumn(
+                cannotMapSpecifiedColumn(
                     (if (keyTable != null) "$keyTable." else "") + keyColumn,
-                    resultColumns.map { it.name }
+                    resultColumns.map { it.name },
+                    androidx.room.MapInfo::class.java.simpleName
                 )
             }
             context.checker.check(
                 valueColumn.isEmpty() || resultColumns.contains(valueColumn, valueTable),
                 queryExecutableElement
             ) {
-                cannotMapInfoSpecifiedColumn(
+                cannotMapSpecifiedColumn(
                     (if (valueTable != null) "$valueTable." else "") + valueColumn,
-                    resultColumns.map { it.name }
+                    resultColumns.map { it.name },
+                    androidx.room.MapInfo::class.java.simpleName
                 )
             }
         }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
index f51988f..f2ec672 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
@@ -60,10 +60,10 @@
         val query = SqlParser.rawQueryForTables(observedTableNames)
         // build the query but don't calculate result info since we just guessed it.
         val resultBinder = delegate.findResultBinder(returnType, query) {
+            @Suppress("DEPRECATION")
             delegate.executableElement.getAnnotation(androidx.room.MapInfo::class)?.let {
-                val keyColumn = it.value.keyColumn.toString()
-                val valueColumn = it.value.valueColumn.toString()
-
+                val keyColumn = it.value.keyColumn
+                val valueColumn = it.value.valueColumn
                 context.checker.check(
                     keyColumn.isNotEmpty() || valueColumn.isNotEmpty(),
                     executableElement,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
index d6e4dcb..614b818 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
@@ -77,6 +77,7 @@
 import androidx.room.solver.query.result.MapQueryResultAdapter
 import androidx.room.solver.query.result.MapValueResultAdapter
 import androidx.room.solver.query.result.MultimapQueryResultAdapter
+import androidx.room.solver.query.result.MultimapQueryResultAdapter.Companion.getMapColumnName
 import androidx.room.solver.query.result.MultimapQueryResultAdapter.Companion.validateMapKeyTypeArg
 import androidx.room.solver.query.result.MultimapQueryResultAdapter.Companion.validateMapValueTypeArg
 import androidx.room.solver.query.result.MultimapQueryResultAdapter.MapType.Companion.isSparseArray
@@ -624,29 +625,40 @@
 
             // Get @MapInfo info if any (this might be null)
             val mapInfo = extras.getData(MapInfo::class)
+            val mapKeyColumn = getMapColumnName(context, query, keyTypeArg)
+            val mapValueColumn = getMapColumnName(context, query, valueTypeArg)
+            if (mapInfo != null && (mapKeyColumn != null || mapValueColumn != null)) {
+                context.logger.e(
+                    ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+                )
+            }
+
+            val mappedKeyColumnName = mapKeyColumn ?: mapInfo?.keyColumnName
+            val mappedValueColumnName = mapValueColumn ?: mapInfo?.valueColumnName
+
             val keyRowAdapter = findRowAdapter(
                 typeMirror = keyTypeArg,
                 query = query,
-                columnName = mapInfo?.keyColumnName
+                columnName = mappedKeyColumnName
             ) ?: return null
 
             val valueRowAdapter = findRowAdapter(
                 typeMirror = valueTypeArg,
                 query = query,
-                columnName = mapInfo?.valueColumnName
+                columnName = mappedValueColumnName
             ) ?: return null
 
             validateMapKeyTypeArg(
                 context = context,
                 keyTypeArg = keyTypeArg,
                 keyReader = findCursorValueReader(keyTypeArg, null),
-                mapInfo = mapInfo
+                keyColumnName = mappedKeyColumnName
             )
             validateMapValueTypeArg(
                 context = context,
                 valueTypeArg = valueTypeArg,
                 valueReader = findCursorValueReader(valueTypeArg, null),
-                mapInfo = mapInfo
+                valueColumnName = mappedValueColumnName
             )
             return GuavaImmutableMultimapQueryResultAdapter(
                 context = context,
@@ -694,18 +706,25 @@
 
             // Get @MapInfo info if any (this might be null)
             val mapInfo = extras.getData(MapInfo::class)
+            val mapColumn = getMapColumnName(context, query, keyTypeArg)
+            if (mapInfo != null && mapColumn != null) {
+                context.logger.e(
+                    ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+                )
+            }
 
+            val mappedKeyColumnName = mapColumn ?: mapInfo?.keyColumnName
             val keyRowAdapter = findRowAdapter(
                 typeMirror = keyTypeArg,
                 query = query,
-                columnName = mapInfo?.keyColumnName
+                columnName = mappedKeyColumnName
             ) ?: return null
 
             validateMapKeyTypeArg(
                 context = context,
                 keyTypeArg = keyTypeArg,
                 keyReader = findCursorValueReader(keyTypeArg, null),
-                mapInfo = mapInfo
+                keyColumnName = mappedKeyColumnName
             )
 
             val mapValueResultAdapter = findMapValueResultAdapter(
@@ -801,17 +820,25 @@
             }
 
             val valueTypeArg = mapValueTypeArg.typeArguments.single().extendsBoundOrSelf()
+            val mapColumnName = getMapColumnName(context, query, valueTypeArg)
+            if (mapColumnName != null && mapInfo != null) {
+                context.logger.e(
+                    ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+                )
+            }
+
+            val mappedValueColumnName = mapColumnName ?: mapInfo?.valueColumnName
             val valueRowAdapter = findRowAdapter(
                 typeMirror = valueTypeArg,
                 query = query,
-                columnName = mapInfo?.valueColumnName
+                columnName = mappedValueColumnName
             ) ?: return null
 
             validateMapValueTypeArg(
                 context = context,
                 valueTypeArg = valueTypeArg,
                 valueReader = findCursorValueReader(valueTypeArg, null),
-                mapInfo = mapInfo
+                valueColumnName = mappedValueColumnName
             )
 
             return MapValueResultAdapter.EndMapValueResultAdapter(
@@ -821,14 +848,19 @@
             )
         } else if (mapValueTypeArg.isTypeOf(java.util.Map::class)) {
             val keyTypeArg = mapValueTypeArg.typeArguments[0].extendsBoundOrSelf()
+            val valueTypeArg = mapValueTypeArg.typeArguments[1].extendsBoundOrSelf()
+
             val keyRowAdapter = findRowAdapter(
                 typeMirror = keyTypeArg,
                 query = query,
-                columnName = null
+                // No need to account for @MapInfo since nested maps did not support
+                // this now deprecated annotation anyway.
+                columnName = getMapColumnName(context, query, keyTypeArg)
             ) ?: return null
-            val valueTypeArg = mapValueTypeArg.typeArguments[1].extendsBoundOrSelf()
             val valueMapAdapter = findMapValueResultAdapter(
-                query, mapInfo, valueTypeArg
+                query = query,
+                mapInfo = mapInfo,
+                mapValueTypeArg = valueTypeArg
             ) ?: return null
             return MapValueResultAdapter.NestedMapValueResultAdapter(
                 keyRowAdapter = keyRowAdapter,
@@ -837,17 +869,19 @@
                 mapValueResultAdapter = valueMapAdapter
             )
         } else {
+            val mappedValueColumnName = getMapColumnName(context, query, mapValueTypeArg)
+                ?: mapInfo?.valueColumnName
             val valueRowAdapter = findRowAdapter(
                 typeMirror = mapValueTypeArg,
                 query = query,
-                columnName = mapInfo?.valueColumnName
+                columnName = mappedValueColumnName
             ) ?: return null
 
             validateMapValueTypeArg(
                 context = context,
                 valueTypeArg = mapValueTypeArg,
                 valueReader = findCursorValueReader(mapValueTypeArg, null),
-                mapInfo = mapInfo
+                valueColumnName = mappedValueColumnName
             )
             return MapValueResultAdapter.EndMapValueResultAdapter(
                 valueRowAdapter = valueRowAdapter,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MapValueResultAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MapValueResultAdapter.kt
index 3d77078..a758ff4 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MapValueResultAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MapValueResultAdapter.kt
@@ -340,8 +340,12 @@
                             language == CodeLanguage.KOTLIN &&
                             valueTypeArg.nullability == XNullability.NONNULL
                         ) {
-                            // TODO(b/249984504): Generate / output a better message.
-                            addStatement("error(%S)", "Missing value for a key.")
+                            addStatement(
+                                "error(%S)",
+                                "The column(s) of the map value object of type " +
+                                    "'$valueTypeArg' are NULL but the map's value type " +
+                                    "argument expect it to be NON-NULL"
+                            )
                         } else {
                             genPutValueCode.invoke("null", false)
                             addStatement("continue")
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultimapQueryResultAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultimapQueryResultAdapter.kt
index c5791df..1d71248 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultimapQueryResultAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultimapQueryResultAdapter.kt
@@ -16,9 +16,11 @@
 
 package androidx.room.solver.query.result
 
+import androidx.room.MapColumn
 import androidx.room.compiler.codegen.CodeLanguage
 import androidx.room.compiler.codegen.XClassName
 import androidx.room.compiler.codegen.XCodeBlock
+import androidx.room.compiler.codegen.asClassName
 import androidx.room.compiler.processing.XType
 import androidx.room.ext.CollectionTypeNames
 import androidx.room.ext.CommonTypeNames
@@ -30,8 +32,8 @@
 import androidx.room.processor.ProcessorErrors.AmbiguousColumnLocation.MAP_INFO
 import androidx.room.processor.ProcessorErrors.AmbiguousColumnLocation.POJO
 import androidx.room.solver.types.CursorValueReader
+import androidx.room.verifier.ColumnInfo
 import androidx.room.vo.ColumnIndexVar
-import androidx.room.vo.MapInfo
 import androidx.room.vo.Warning
 
 /**
@@ -118,14 +120,14 @@
     companion object {
 
         /**
-         * Checks if the @MapInfo annotation is needed for clarification regarding the key type
+         * Checks if the @MapColumn annotation is needed for clarification regarding the key type
          * arg of a Map return type.
          */
         fun validateMapKeyTypeArg(
             context: Context,
             keyTypeArg: XType,
             keyReader: CursorValueReader?,
-            mapInfo: MapInfo?,
+            keyColumnName: String?,
         ) {
             if (!keyTypeArg.implementsEqualsAndHashcode()) {
                 context.logger.w(
@@ -136,10 +138,10 @@
                 )
             }
 
-            val hasKeyColumnName = mapInfo?.keyColumnName?.isNotEmpty() ?: false
+            val hasKeyColumnName = keyColumnName?.isNotEmpty() ?: false
             if (!hasKeyColumnName && keyReader != null) {
                 context.logger.e(
-                    ProcessorErrors.keyMayNeedMapInfo(
+                    ProcessorErrors.mayNeedMapColumn(
                         keyTypeArg.asTypeName().toString(context.codeLanguage)
                     )
                 )
@@ -147,24 +149,68 @@
         }
 
         /**
-         * Checks if the @MapInfo annotation is needed for clarification regarding the value type
+         * Checks if the @MapColumn annotation is needed for clarification regarding the value type
          * arg of a Map return type.
          */
         fun validateMapValueTypeArg(
             context: Context,
             valueTypeArg: XType,
             valueReader: CursorValueReader?,
-            mapInfo: MapInfo?,
+            valueColumnName: String?,
         ) {
-            val hasValueColumnName = mapInfo?.valueColumnName?.isNotEmpty() ?: false
+            val hasValueColumnName = valueColumnName?.isNotEmpty() ?: false
             if (!hasValueColumnName && valueReader != null) {
                 context.logger.e(
-                    ProcessorErrors.valueMayNeedMapInfo(
+                    ProcessorErrors.mayNeedMapColumn(
                         valueTypeArg.asTypeName().toString(context.codeLanguage)
                     )
                 )
             }
         }
+
+        /**
+         * Retrieves the `columnName` value from a @MapColumn annotation.
+         */
+        fun getMapColumnName(context: Context, query: ParsedQuery, type: XType): String? {
+            val resultColumns = query.resultInfo?.columns
+            val resultTableAliases = query.tables.associate { it.name to it.alias }
+            val annotation = type.getAnnotation(MapColumn::class.asClassName()) ?: return null
+
+            val mapColumnName = annotation.getAsString("columnName")
+            val mapColumnTableName = annotation.getAsString("tableName")
+
+            fun List<ColumnInfo>.contains(
+                columnName: String,
+                tableName: String?
+            ) = any { resultColumn ->
+                val resultTableAlias = resultColumn.originTable?.let {
+                    resultTableAliases[it] ?: it
+                }
+                resultColumn.name == columnName && (
+                    if (!tableName.isNullOrEmpty()) {
+                        resultTableAlias == tableName || resultColumn.originTable == tableName
+                    } else true)
+            }
+
+            if (resultColumns != null) {
+                // Disambiguation check for MapColumn
+                if (!resultColumns.contains(mapColumnName, mapColumnTableName)) {
+                    val errorColumn = if (mapColumnTableName.isNotEmpty()) {
+                        "$mapColumnTableName."
+                    } else {
+                        ""
+                    } + mapColumnName
+                    context.logger.e(
+                        ProcessorErrors.cannotMapSpecifiedColumn(
+                            errorColumn,
+                            resultColumns.map { it.name },
+                            MapColumn::class.java.simpleName
+                        )
+                    )
+                }
+            }
+            return mapColumnName
+        }
     }
 
     /**
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleItemQueryResultAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleItemQueryResultAdapter.kt
index b9fdcbb..519ff4a 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleItemQueryResultAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleItemQueryResultAdapter.kt
@@ -41,8 +41,11 @@
                     type.nullability == XNullability.NONNULL &&
                     defaultValue == "null"
                 ) {
-                    // TODO(b/249984504): Generate / output a better message.
-                    addStatement("error(%S)", "Cursor was empty, but expected a single item.")
+                    addStatement(
+                        "error(%S)", "The query result was empty, but expected a single row to " +
+                            "return a NON-NULL object of " +
+                            "type <${type.asTypeName().toString(language)}>."
+                    )
                 } else {
                     addStatement("%L = %L", outVarName, rowAdapter.out.defaultValue())
                 }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/types/NullAwareTypeConverters.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/types/NullAwareTypeConverters.kt
index 7d2196e..03c641c 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/types/NullAwareTypeConverters.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/types/NullAwareTypeConverters.kt
@@ -93,7 +93,7 @@
 
     private fun XCodeBlock.Builder.addIllegalStateException() {
         val typeName = from.asTypeName().copy(nullable = false).toString(language)
-        val message = "Expected non-null $typeName, but it was null."
+        val message = "Expected NON-NULL '$typeName', but it was NULL."
         when (language) {
             CodeLanguage.JAVA -> {
                 addStatement(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/types/ValueClassConverterWrapper.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/types/ValueClassConverterWrapper.kt
index cc2d6ee..831520d 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/types/ValueClassConverterWrapper.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/types/ValueClassConverterWrapper.kt
@@ -80,13 +80,13 @@
         scope.builder.apply {
             val propertyName = scope.getTmpVar("_$valuePropertyName")
             val assignmentBlock = if (out.nullability == XNullability.NONNULL) {
-                // TODO(b/249984504): Generate / output a better message.
                 XCodeBlock.of(
                     scope.language,
                     "checkNotNull(%L.%L) { %S }",
                     valueVarName,
                     valuePropertyName,
-                    "Cannot bind nullable value of inline class to a NOT NULL column."
+                    "Cannot bind NULLABLE value '$valuePropertyName' of inline " +
+                        "class '$out' to a NOT NULL column."
                 )
             } else {
                 XCodeBlock.of(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
index dce1f83..eceddad 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
@@ -174,8 +174,13 @@
                         addStatement("%L = %L.get(%L)", tmpRelationVar, varName, tmpKeyVar)
                         if (language == CodeLanguage.KOTLIN && relation.field.nonNull) {
                             beginControlFlow("if (%L == null)", tmpRelationVar)
-                            // TODO(b/249984504): Generate / output a better message.
-                            addStatement("error(%S)", "Missing relationship item.")
+                            addStatement(
+                                "error(%S)",
+                                "Relationship item '${relation.field.name}' was expected to" +
+                                    " be NON-NULL but is NULL in @Relation involving " +
+                                "a parent column named '${relation.parentField.columnName}' and " +
+                                    "entityColumn named '${relation.entityField.columnName}'."
+                            )
                             endControlFlow()
                         }
                     }
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityDeletionAdapterWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityDeletionAdapterWriter.kt
index d1d1379..204bc48 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityDeletionAdapterWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityDeletionAdapterWriter.kt
@@ -60,7 +60,7 @@
                 XFunSpec.builder(
                     language = language,
                     name = "createQuery",
-                    visibility = VisibilityModifier.PUBLIC,
+                    visibility = VisibilityModifier.PROTECTED,
                     isOverride = true
                 ).apply {
                     returns(CommonTypeNames.STRING)
@@ -73,7 +73,7 @@
                 XFunSpec.builder(
                     language = language,
                     name = "bind",
-                    visibility = VisibilityModifier.PUBLIC,
+                    visibility = VisibilityModifier.PROTECTED,
                     isOverride = true
                 ).apply {
                     val stmtParam = "statement"
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityInsertionAdapterWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityInsertionAdapterWriter.kt
index 5e2b01f..3a6d684 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityInsertionAdapterWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityInsertionAdapterWriter.kt
@@ -75,7 +75,7 @@
                 XFunSpec.builder(
                     language = language,
                     name = "createQuery",
-                    visibility = VisibilityModifier.PUBLIC,
+                    visibility = VisibilityModifier.PROTECTED,
                     isOverride = true
                 ).apply {
                     returns(CommonTypeNames.STRING)
@@ -105,7 +105,7 @@
                 XFunSpec.builder(
                     language = language,
                     name = "bind",
-                    visibility = VisibilityModifier.PUBLIC,
+                    visibility = VisibilityModifier.PROTECTED,
                     isOverride = true
                 ).apply {
                     returns(XTypeName.UNIT_VOID)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityUpdateAdapterWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityUpdateAdapterWriter.kt
index c7f487c..f06592d 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityUpdateAdapterWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityUpdateAdapterWriter.kt
@@ -53,7 +53,7 @@
                 XFunSpec.builder(
                     language = language,
                     name = "createQuery",
-                    visibility = VisibilityModifier.PUBLIC,
+                    visibility = VisibilityModifier.PROTECTED,
                     isOverride = true
                 ).apply {
                     returns(CommonTypeNames.STRING)
@@ -80,7 +80,7 @@
                 XFunSpec.builder(
                     language = language,
                     name = "bind",
-                    visibility = VisibilityModifier.PUBLIC,
+                    visibility = VisibilityModifier.PROTECTED,
                     isOverride = true
                 ).apply {
                     val stmtParam = "statement"
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
index 8b856c3..b523301 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
@@ -373,10 +373,10 @@
                         typeName.nullability == XNullability.NONNULL &&
                         defaultValue == "null"
                     ) {
-                        // TODO(b/249984504): Generate / output a better message.
                         addStatement(
                             "error(%S)",
-                            "Missing column '${field.columnName}' for a non null value."
+                            "Missing value for a NON-NULL column '${field.columnName}', " +
+                                "found NULL value instead."
                         )
                     } else {
                         addStatement("%L = %L", tmpField, defaultValue)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
index 13d0293..9c40b99 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
@@ -41,11 +41,11 @@
 import androidx.room.ext.RxJava3TypeNames
 import androidx.room.parser.QueryType
 import androidx.room.parser.Table
+import androidx.room.processor.ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
 import androidx.room.processor.ProcessorErrors.DO_NOT_USE_GENERIC_IMMUTABLE_MULTIMAP
 import androidx.room.processor.ProcessorErrors.MAP_INFO_MUST_HAVE_AT_LEAST_ONE_COLUMN_PROVIDED
 import androidx.room.processor.ProcessorErrors.cannotFindQueryResultAdapter
-import androidx.room.processor.ProcessorErrors.keyMayNeedMapInfo
-import androidx.room.processor.ProcessorErrors.valueMayNeedMapInfo
+import androidx.room.processor.ProcessorErrors.mayNeedMapColumn
 import androidx.room.solver.query.result.DataSourceFactoryQueryResultBinder
 import androidx.room.solver.query.result.ListQueryResultAdapter
 import androidx.room.solver.query.result.LiveDataQueryResultBinder
@@ -1305,7 +1305,7 @@
             DAO_PREFIX + input.joinToString("\n") + DAO_SUFFIX
         )
         val commonSources = listOf(
-            COMMON.LIVE_DATA, COMMON.COMPUTABLE_LIVE_DATA, COMMON.USER, COMMON.BOOK,
+            COMMON.LIVE_DATA, COMMON.COMPUTABLE_LIVE_DATA, COMMON.USER, COMMON.BOOK, COMMON.PAGE,
             COMMON.NOT_AN_ENTITY, COMMON.ARTIST, COMMON.SONG, COMMON.IMAGE, COMMON.IMAGE_FORMAT,
             COMMON.CONVERTER
         )
@@ -1511,6 +1511,131 @@
     }
 
     @Test
+    fun testUseMapColumnWithColumnName() {
+        if (!enableVerification) {
+            return
+        }
+        singleQueryMethod<ReadQueryMethod>(
+            """
+                @SuppressWarnings(
+                    {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+                )
+                @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid")
+                abstract Map<@MapColumn(columnName = "uid") Integer, Book> getMultimap();
+            """
+        ) { _, invocation ->
+            invocation.assertCompilationResult {
+                hasNoWarnings()
+            }
+        }
+    }
+
+    @Test
+    fun testUseMapColumnWithColumnNameWrongTableName() {
+        if (!enableVerification) {
+            return
+        }
+        singleQueryMethod<ReadQueryMethod>(
+            """
+                @SuppressWarnings(
+                    {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+                )
+                @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid")
+                abstract Map<@MapColumn(columnName = "uid", tableName = "NoName") Integer, Book> getMultimap();
+            """
+        ) { _, invocation ->
+            invocation.assertCompilationResult {
+                hasErrorContaining(
+                    "Column specified in the provided @MapColumn " +
+                    "annotation must be present in the query."
+                )
+            }
+        }
+    }
+
+    @Test
+    fun testUseNestedMapColumnWithColumnName() {
+        if (!enableVerification) {
+            return
+        }
+        singleQueryMethod<ReadQueryMethod>(
+            """
+                @SuppressWarnings(
+                    {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+                )
+                @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid JOIN Page on b.uid == pBid")
+                abstract Map<@MapColumn(columnName = "uid") Integer, Map<Book, @MapColumn(columnName = "pBid") Integer>> getMultimap();
+            """
+        ) { _, invocation ->
+            invocation.assertCompilationResult {
+                hasNoWarnings()
+            }
+        }
+    }
+
+    @Test
+    fun testUseNestedMapColumnWithNestedKeyColumnName() {
+        if (!enableVerification) {
+            return
+        }
+        singleQueryMethod<ReadQueryMethod>(
+            """
+                @SuppressWarnings(
+                    {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+                )
+                @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid JOIN Page on b.uid == pBid")
+                abstract Map<@MapColumn(columnName = "uid") Integer, Map<@MapColumn(columnName = "bookId") Integer, @MapColumn(columnName = "pBid") Integer>> getMultimap();
+            """
+        ) { _, invocation ->
+            invocation.assertCompilationResult {
+                hasNoWarnings()
+            }
+        }
+    }
+
+    @Test
+    fun testUseMapColumnWithColumnAlias() {
+        if (!enableVerification) {
+            return
+        }
+        singleQueryMethod<ReadQueryMethod>(
+            """
+                @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
+                @Query("SELECT name, (SELECT count(*) FROM User u JOIN Book b ON u.uid == b.uid) "
+                    + "AS bookCount FROM User")
+                abstract Map<@MapColumn(columnName = "name") String, @MapColumn(columnName = "bookCount") Integer> getMultimap();
+            """
+        ) { _, invocation ->
+            invocation.assertCompilationResult {
+                hasNoWarnings()
+            }
+        }
+    }
+
+    @Test
+    fun testCannotHaveMapInfoAndMapColumn() {
+        if (!enableVerification) {
+            return
+        }
+        singleQueryMethod<ReadQueryMethod>(
+            """
+                @SuppressWarnings(
+                    {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+                )
+                @MapInfo(keyColumn = "uid", keyTable = "u")
+                @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid")
+                abstract Map<@MapColumn(columnName = "uid") Integer, Book> getMultimap();
+            """
+        ) { _, invocation ->
+            invocation.assertCompilationResult {
+                hasErrorContaining(
+                    CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+                )
+            }
+        }
+    }
+
+    @Test
     fun testDoesNotImplementEqualsAndHashcodeQuery() {
         singleQueryMethod<ReadQueryMethod>(
             """
@@ -1539,7 +1664,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    valueMayNeedMapInfo(CommonTypeNames.STRING.canonicalName)
+                    mayNeedMapColumn(STRING.canonicalName)
                 )
             }
         }
@@ -1556,7 +1681,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    valueMayNeedMapInfo(CommonTypeNames.STRING.canonicalName)
+                    mayNeedMapColumn(STRING.canonicalName)
                 )
             }
         }
@@ -1572,7 +1697,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    valueMayNeedMapInfo(CommonTypeNames.STRING.canonicalName)
+                    mayNeedMapColumn(STRING.canonicalName)
                 )
             }
         }
@@ -1588,7 +1713,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    valueMayNeedMapInfo(CommonTypeNames.STRING.canonicalName)
+                    mayNeedMapColumn(STRING.canonicalName)
                 )
             }
         }
@@ -1604,7 +1729,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+                    mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
                 )
             }
         }
@@ -1620,7 +1745,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+                    mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
                 )
             }
         }
@@ -1636,7 +1761,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+                    mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
                 )
             }
         }
@@ -1653,7 +1778,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    keyMayNeedMapInfo("java.util.Date")
+                    mayNeedMapColumn("java.util.Date")
                 )
             }
         }
@@ -1670,7 +1795,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    valueMayNeedMapInfo("java.util.Date")
+                    mayNeedMapColumn("java.util.Date")
                 )
             }
         }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
index 291267e..805c6ea 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
@@ -423,7 +423,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    ProcessorErrors.valueMayNeedMapInfo(
+                    ProcessorErrors.mayNeedMapColumn(
                         CommonTypeNames.STRING.canonicalName
                     )
                 )
@@ -441,7 +441,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    ProcessorErrors.valueMayNeedMapInfo(
+                    ProcessorErrors.mayNeedMapColumn(
                         CommonTypeNames.STRING.canonicalName
                     )
                 )
@@ -459,7 +459,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    ProcessorErrors.valueMayNeedMapInfo(
+                    ProcessorErrors.mayNeedMapColumn(
                         CommonTypeNames.STRING.canonicalName
                     )
                 )
@@ -477,7 +477,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    ProcessorErrors.valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+                    ProcessorErrors.mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
                 )
             }
         }
@@ -493,7 +493,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    ProcessorErrors.valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+                    ProcessorErrors.mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
                 )
             }
         }
@@ -509,7 +509,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    ProcessorErrors.valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+                    ProcessorErrors.mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
                 )
             }
         }
@@ -526,7 +526,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    ProcessorErrors.keyMayNeedMapInfo("java.util.Date")
+                    ProcessorErrors.mayNeedMapColumn("java.util.Date")
                 )
             }
         }
@@ -543,7 +543,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    ProcessorErrors.valueMayNeedMapInfo("java.util.Date")
+                    ProcessorErrors.mayNeedMapColumn("java.util.Date")
                 )
             }
         }
@@ -560,7 +560,7 @@
         ) { _, invocation ->
             invocation.assertCompilationResult {
                 hasErrorContaining(
-                    ProcessorErrors.valueMayNeedMapInfo(
+                    ProcessorErrors.mayNeedMapColumn(
                         CommonTypeNames.STRING.canonicalName
                     )
                 )
@@ -569,6 +569,47 @@
     }
 
     @Test
+    fun testUseMapColumnWithColumnName() {
+        singleQueryMethod(
+            """
+                @SuppressWarnings(
+                    {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+                )
+                @RawQuery
+                abstract Map<@MapColumn(columnName = "uid") Integer, Book> getMultimap(
+                    SupportSQLiteQuery query
+                );
+            """
+        ) { _, invocation ->
+            invocation.assertCompilationResult {
+                hasNoWarnings()
+            }
+        }
+    }
+
+    @Test
+    fun testCannotHaveMapInfoAndMapColumn() {
+        singleQueryMethod(
+            """
+                @SuppressWarnings(
+                    {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+                )
+                @MapInfo(keyColumn = "uid", keyTable = "u")
+                @RawQuery
+                abstract Map<@MapColumn(columnName = "uid") Integer, Book> getMultimap(
+                    SupportSQLiteQuery query
+                );
+            """
+        ) { _, invocation ->
+            invocation.assertCompilationResult {
+                hasErrorContaining(
+                    ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+                )
+            }
+        }
+    }
+
+    @Test
     fun suspendReturnsDeferredType() {
         listOf(
             "${RxJava2TypeNames.FLOWABLE.canonicalName}<Int>",
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt b/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt
index b98bcfd6..688ff71 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt
@@ -78,6 +78,11 @@
     val BOOK by lazy {
         loadJavaCode("common/input/Book.java", "foo.bar.Book")
     }
+
+    val PAGE by lazy {
+        loadJavaCode("common/input/Page.java", "foo.bar.Page")
+    }
+
     val NOT_AN_ENTITY by lazy {
         loadJavaCode("common/input/NotAnEntity.java", "foo.bar.NotAnEntity")
     }
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
index 9c2d88c..ca22005 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
@@ -1483,6 +1483,7 @@
                 @Query("SELECT * FROM Artist JOIN Song ON Artist.artistId = Song.artistKey")
                 fun getArtistWithSongs(): Map<Artist, List<Song>>
 
+                @Suppress("DEPRECATION") // For @MapInfo
                 @MapInfo(valueColumn = "songCount")
                 @Query(
                     "SELECT Artist.*, COUNT(songId) as songCount " +
@@ -1492,6 +1493,7 @@
                 fun getArtistSongCount(): Map<Artist, Int>
 
                 @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
+                @Suppress("DEPRECATION") // For @MapInfo
                 @MapInfo(valueColumn = "songId")
                 @Query("SELECT * FROM Artist JOIN Song ON Artist.artistId = Song.artistKey")
                 fun getArtistWithSongIds(): Map<Artist, List<String>>
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/room/room-compiler/src/test/test-data/common/input/Page.java
similarity index 61%
copy from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
copy to room/room-compiler/src/test/test-data/common/input/Page.java
index 31d0e6f..e9937cb 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/room/room-compiler/src/test/test-data/common/input/Page.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,14 +14,11 @@
  * limitations under the License.
  */
 
-package androidx.lifecycle.observers;
-
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
-    @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
-    void onCreate();
+package foo.bar;
+import androidx.room.*;
+@Entity
+public class Page {
+    @PrimaryKey
+    int pageId;
+    int pBid;
 }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java
index 598d267..31272dc 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java
@@ -43,24 +43,24 @@
         this.__deletionAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "DELETE FROM `User` WHERE `uid` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
                 statement.bindLong(1, entity.uid);
             }
         };
         this.__deletionAdapterOfMultiPKeyEntity = new EntityDeletionOrUpdateAdapter<MultiPKeyEntity>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "DELETE FROM `MultiPKeyEntity` WHERE `name` = ? AND `lastName` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     final MultiPKeyEntity entity) {
                 if (entity.name == null) {
                     statement.bindNull(1);
@@ -77,12 +77,12 @@
         this.__deletionAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "DELETE FROM `Book` WHERE `bookId` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
                 statement.bindLong(1, entity.bookId);
             }
         };
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java
index e3b6103..5dbb7eb 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java
@@ -43,12 +43,12 @@
         this.__updateAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE OR ABORT `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
                 statement.bindLong(1, entity.uid);
                 if (entity.name == null) {
                     statement.bindNull(2);
@@ -67,12 +67,12 @@
         this.__updateAdapterOfUser_1 = new EntityDeletionOrUpdateAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
                 statement.bindLong(1, entity.uid);
                 if (entity.name == null) {
                     statement.bindNull(2);
@@ -91,12 +91,12 @@
         this.__updateAdapterOfMultiPKeyEntity = new EntityDeletionOrUpdateAdapter<MultiPKeyEntity>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE OR ABORT `MultiPKeyEntity` SET `name` = ?,`lastName` = ? WHERE `name` = ? AND `lastName` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     final MultiPKeyEntity entity) {
                 if (entity.name == null) {
                     statement.bindNull(1);
@@ -123,12 +123,12 @@
         this.__updateAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE OR ABORT `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
                 statement.bindLong(1, entity.bookId);
                 statement.bindLong(2, entity.uid);
                 statement.bindLong(3, entity.bookId);
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpsertDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpsertDao.java
index 1e7255b..4d4875a 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpsertDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpsertDao.java
@@ -28,12 +28,12 @@
         this.__upsertionAdapterOfUser = new EntityUpsertionAdapter<User>(new EntityInsertionAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
                 statement.bindLong(1, entity.uid);
                 if (entity.name == null) {
                     statement.bindNull(2);
@@ -50,12 +50,12 @@
         }, new EntityDeletionOrUpdateAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
                 statement.bindLong(1, entity.uid);
                 if (entity.name == null) {
                     statement.bindNull(2);
@@ -74,24 +74,24 @@
         this.__upsertionAdapterOfBook = new EntityUpsertionAdapter<Book>(new EntityInsertionAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
                 statement.bindLong(1, entity.bookId);
                 statement.bindLong(2, entity.uid);
             }
         }, new EntityDeletionOrUpdateAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
                 statement.bindLong(1, entity.bookId);
                 statement.bindLong(2, entity.uid);
                 statement.bindLong(3, entity.bookId);
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/WriterDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/WriterDao.java
index ddbbe73..3287dd2 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/WriterDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/WriterDao.java
@@ -30,12 +30,12 @@
         this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT OR ABORT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
                 statement.bindLong(1, entity.uid);
                 if (entity.name == null) {
                     statement.bindNull(2);
@@ -53,12 +53,12 @@
         this.__insertionAdapterOfUser_1 = new EntityInsertionAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT OR REPLACE INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
                 statement.bindLong(1, entity.uid);
                 if (entity.name == null) {
                     statement.bindNull(2);
@@ -76,12 +76,12 @@
         this.__insertionAdapterOfUser_2 = new EntityInsertionAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
                 statement.bindLong(1, entity.uid);
                 if (entity.name == null) {
                     statement.bindNull(2);
@@ -99,12 +99,12 @@
         this.__insertionAdapterOfBook = new EntityInsertionAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT OR ABORT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+            protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
                 statement.bindLong(1, entity.bookId);
                 statement.bindLong(2, entity.uid);
             }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
index 4fa7155..45fee3b 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
@@ -43,12 +43,12 @@
         this.__deletionAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "DELETE FROM `User` WHERE `uid` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final User entity) {
                 statement.bindLong(1, entity.uid);
             }
@@ -56,12 +56,12 @@
         this.__deletionAdapterOfMultiPKeyEntity = new EntityDeletionOrUpdateAdapter<MultiPKeyEntity>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "DELETE FROM `MultiPKeyEntity` WHERE `name` = ? AND `lastName` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final MultiPKeyEntity entity) {
                 statement.bindString(1, entity.name);
                 statement.bindString(2, entity.lastName);
@@ -70,12 +70,12 @@
         this.__deletionAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "DELETE FROM `Book` WHERE `bookId` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final Book entity) {
                 statement.bindLong(1, entity.bookId);
             }
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
index 571e245..1fb23be 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
@@ -43,12 +43,12 @@
         this.__updateAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE OR ABORT `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final User entity) {
                 statement.bindLong(1, entity.uid);
                 statement.bindString(2, entity.name);
@@ -60,12 +60,12 @@
         this.__updateAdapterOfUser_1 = new EntityDeletionOrUpdateAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final User entity) {
                 statement.bindLong(1, entity.uid);
                 statement.bindString(2, entity.name);
@@ -77,12 +77,12 @@
         this.__updateAdapterOfMultiPKeyEntity = new EntityDeletionOrUpdateAdapter<MultiPKeyEntity>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE OR ABORT `MultiPKeyEntity` SET `name` = ?,`lastName` = ? WHERE `name` = ? AND `lastName` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final MultiPKeyEntity entity) {
                 statement.bindString(1, entity.name);
                 statement.bindString(2, entity.lastName);
@@ -93,12 +93,12 @@
         this.__updateAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE OR ABORT `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final Book entity) {
                 statement.bindLong(1, entity.bookId);
                 statement.bindLong(2, entity.uid);
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java
index 8a1374c..80b1ba9 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java
@@ -28,12 +28,12 @@
         this.__upsertionAdapterOfUser = new EntityUpsertionAdapter<User>(new EntityInsertionAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final User entity) {
                 statement.bindLong(1, entity.uid);
                 statement.bindString(2, entity.name);
@@ -43,12 +43,12 @@
         }, new EntityDeletionOrUpdateAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final User entity) {
                 statement.bindLong(1, entity.uid);
                 statement.bindString(2, entity.name);
@@ -60,12 +60,12 @@
         this.__upsertionAdapterOfBook = new EntityUpsertionAdapter<Book>(new EntityInsertionAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final Book entity) {
                 statement.bindLong(1, entity.bookId);
                 statement.bindLong(2, entity.uid);
@@ -73,12 +73,12 @@
         }, new EntityDeletionOrUpdateAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "UPDATE `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final Book entity) {
                 statement.bindLong(1, entity.bookId);
                 statement.bindLong(2, entity.uid);
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java
index 54443ae..a0601f1 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java
@@ -30,12 +30,12 @@
         this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT OR ABORT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final User entity) {
                 statement.bindLong(1, entity.uid);
                 statement.bindString(2, entity.name);
@@ -46,12 +46,12 @@
         this.__insertionAdapterOfUser_1 = new EntityInsertionAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT OR REPLACE INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final User entity) {
                 statement.bindLong(1, entity.uid);
                 statement.bindString(2, entity.name);
@@ -62,12 +62,12 @@
         this.__insertionAdapterOfUser_2 = new EntityInsertionAdapter<User>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final User entity) {
                 statement.bindLong(1, entity.uid);
                 statement.bindString(2, entity.name);
@@ -78,12 +78,12 @@
         this.__insertionAdapterOfBook = new EntityInsertionAdapter<Book>(__db) {
             @Override
             @NonNull
-            public String createQuery() {
+            protected String createQuery() {
                 return "INSERT OR ABORT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
             }
 
             @Override
-            public void bind(@NonNull final SupportSQLiteStatement statement,
+            protected void bind(@NonNull final SupportSQLiteStatement statement,
                     @NonNull final Book entity) {
                 statement.bindLong(1, entity.bookId);
                 statement.bindLong(2, entity.uid);
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/abstractClassWithParam.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/abstractClassWithParam.kt
index d306558..1caa291 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/abstractClassWithParam.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/abstractClassWithParam.kt
@@ -35,7 +35,7 @@
                 _tmpPk = _cursor.getInt(_cursorIndexOfPk)
                 _result = MyEntity(_tmpPk)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/arrayParameterAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/arrayParameterAdapter.kt
index d415b37..27b158e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/arrayParameterAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/arrayParameterAdapter.kt
@@ -51,7 +51,7 @@
                 _tmpId = _cursor.getString(_cursorIndexOfId)
                 _result = MyEntity(_tmpId)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -88,7 +88,7 @@
                 _tmpId = _cursor.getString(_cursorIndexOfId)
                 _result = MyEntity(_tmpId)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -125,7 +125,7 @@
                 _tmpId = _cursor.getString(_cursorIndexOfId)
                 _result = MyEntity(_tmpId)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -158,7 +158,7 @@
                 _tmpId = _cursor.getString(_cursorIndexOfId)
                 _result = MyEntity(_tmpId)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -195,7 +195,7 @@
                 _tmpId = _cursor.getString(_cursorIndexOfId)
                 _result = MyEntity(_tmpId)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -228,7 +228,7 @@
                 _tmpId = _cursor.getString(_cursorIndexOfId)
                 _result = MyEntity(_tmpId)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -265,7 +265,7 @@
                 _tmpId = _cursor.getString(_cursorIndexOfId)
                 _result = MyEntity(_tmpId)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/basicParameterAdapter_string.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/basicParameterAdapter_string.kt
index 3b22d23..a8234c8 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/basicParameterAdapter_string.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/basicParameterAdapter_string.kt
@@ -37,7 +37,7 @@
                 _tmpString = _cursor.getString(_cursorIndexOfString)
                 _result = MyEntity(_tmpString)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -65,7 +65,7 @@
                 _tmpString = _cursor.getString(_cursorIndexOfString)
                 _result = MyEntity(_tmpString)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx2.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx2.kt
index fd018379..7cfc96d 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx2.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx2.kt
@@ -64,7 +64,7 @@
                         _tmpOther = _cursor.getString(_cursorIndexOfOther)
                         _result = MyEntity(_tmpPk,_tmpOther)
                     } else {
-                        error("Cursor was empty, but expected a single item.")
+                        error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
                     }
                     return _result
                 } finally {
@@ -110,7 +110,7 @@
                         _tmpOther = _cursor.getString(_cursorIndexOfOther)
                         _result = MyEntity(_tmpPk,_tmpOther)
                     } else {
-                        error("Cursor was empty, but expected a single item.")
+                        error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
                     }
                     return _result
                 } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx3.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx3.kt
index 48492a3..bbd0db3 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx3.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx3.kt
@@ -64,7 +64,7 @@
                         _tmpOther = _cursor.getString(_cursorIndexOfOther)
                         _result = MyEntity(_tmpPk,_tmpOther)
                     } else {
-                        error("Cursor was empty, but expected a single item.")
+                        error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
                     }
                     return _result
                 } finally {
@@ -110,7 +110,7 @@
                         _tmpOther = _cursor.getString(_cursorIndexOfOther)
                         _result = MyEntity(_tmpPk,_tmpOther)
                     } else {
-                        error("Cursor was empty, but expected a single item.")
+                        error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
                     }
                     return _result
                 } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/collectionParameterAdapter_string.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/collectionParameterAdapter_string.kt
index 1d1a468..3c8a547 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/collectionParameterAdapter_string.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/collectionParameterAdapter_string.kt
@@ -50,7 +50,7 @@
                 _tmpString = _cursor.getString(_cursorIndexOfString)
                 _result = MyEntity(_tmpString)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -87,7 +87,7 @@
                 _tmpString = _cursor.getString(_cursorIndexOfString)
                 _result = MyEntity(_tmpString)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -124,7 +124,7 @@
                 _tmpString = _cursor.getString(_cursorIndexOfString)
                 _result = MyEntity(_tmpString)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -157,7 +157,7 @@
                 _tmpString = _cursor.getString(_cursorIndexOfString)
                 _result = MyEntity(_tmpString)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutineResultBinder.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutineResultBinder.kt
index b959c1c..ef15633 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutineResultBinder.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutineResultBinder.kt
@@ -41,7 +41,7 @@
                         _tmpPk = _cursor.getInt(_cursorIndexOfPk)
                         _result = MyEntity(_tmpPk)
                     } else {
-                        error("Cursor was empty, but expected a single item.")
+                        error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
                     }
                     return _result
                 } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
index 3cf1b4c..e09976c 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
@@ -65,7 +65,7 @@
                         _tmpOther = _cursor.getString(_cursorIndexOfOther)
                         _result = MyEntity(_tmpPk,_tmpOther)
                     } else {
-                        error("Cursor was empty, but expected a single item.")
+                        error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
                     }
                     return _result
                 } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt
index e7ff72b..2f5a0cc 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt
@@ -67,7 +67,7 @@
                 _tmpPk = _cursor.getLong(_cursorIndexOfPk)
                 _result = MyEntity(_tmpPk)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_defaultImplBridge.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_defaultImplBridge.kt
index f2b5842..a2792d8 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_defaultImplBridge.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_defaultImplBridge.kt
@@ -36,7 +36,7 @@
                 _tmpPk = _cursor.getLong(_cursorIndexOfPk)
                 _result = MyEntity(_tmpPk)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/deleteOrUpdateMethodAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/deleteOrUpdateMethodAdapter.kt
index 233b23a..890f85e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/deleteOrUpdateMethodAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/deleteOrUpdateMethodAdapter.kt
@@ -22,17 +22,17 @@
     init {
         this.__db = __db
         this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+            protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk)
             }
         }
         this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE OR ABORT `MyEntity` SET `pk` = ?,`data` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk)
                 statement.bindString(2, entity.data)
                 statement.bindLong(3, entity.pk)
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/entityRowAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/entityRowAdapter.kt
index d00f043..bbc3dc0 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/entityRowAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/entityRowAdapter.kt
@@ -27,10 +27,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`valuePrimitive`,`valueBoolean`,`valueString`,`valueNullableString`,`variablePrimitive`,`variableNullableBoolean`,`variableString`,`variableNullableString`) VALUES (?,?,?,?,?,?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.valuePrimitive)
                 val _tmp: Int = if (entity.valueBoolean) 1 else 0
                 statement.bindLong(2, _tmp.toLong())
@@ -81,7 +81,7 @@
             if (_cursor.moveToFirst()) {
                 _result = __entityCursorConverter_MyEntity(_cursor)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
@@ -117,7 +117,7 @@
         }
         val _tmpValueString: String
         if (_cursorIndexOfValueString == -1) {
-            error("Missing column 'valueString' for a non null value.")
+            error("Missing value for a NON-NULL column 'valueString', found NULL value instead.")
         } else {
             _tmpValueString = cursor.getString(_cursorIndexOfValueString)
         }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/guavaCallable.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/guavaCallable.kt
index 3d51fc4..70371f9 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/guavaCallable.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/guavaCallable.kt
@@ -42,26 +42,26 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
             }
         }
         this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+            protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
             }
         }
         this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE OR ABORT `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
                 statement.bindLong(3, entity.pk.toLong())
@@ -69,18 +69,18 @@
         }
         this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
             EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
             }
         }, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
                 statement.bindLong(3, entity.pk.toLong())
@@ -181,7 +181,7 @@
                         _tmpOther = _cursor.getString(_cursorIndexOfOther)
                         _result = MyEntity(_tmpPk,_tmpOther)
                     } else {
-                        error("Cursor was empty, but expected a single item.")
+                        error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
                     }
                     return _result
                 } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/insertOrUpsertMethodAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/insertOrUpsertMethodAdapter.kt
index 246af07..f7ce132 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/insertOrUpsertMethodAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/insertOrUpsertMethodAdapter.kt
@@ -25,28 +25,28 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`data`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk)
                 statement.bindString(2, entity.data)
             }
         }
         this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
             EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT INTO `MyEntity` (`pk`,`data`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk)
                 statement.bindString(2, entity.data)
             }
         }, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE `MyEntity` SET `pk` = ?,`data` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk)
                 statement.bindString(2, entity.data)
                 statement.bindLong(3, entity.pk)
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_boolean.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_boolean.kt
index 0c57f0e..f587b69 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_boolean.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_boolean.kt
@@ -26,10 +26,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`boolean`,`nullableBoolean`) VALUES (?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 val _tmp: Int = if (entity.boolean) 1 else 0
                 statement.bindLong(2, _tmp.toLong())
@@ -82,7 +82,7 @@
                 _tmpNullableBoolean = _tmp_1?.let { it != 0 }
                 _result = MyEntity(_tmpPk,_tmpBoolean,_tmpNullableBoolean)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_byteArray.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_byteArray.kt
index f369507..5c83c9e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_byteArray.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_byteArray.kt
@@ -26,10 +26,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`byteArray`,`nullableByteArray`) VALUES (?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindBlob(2, entity.byteArray)
                 val _tmpNullableByteArray: ByteArray? = entity.nullableByteArray
@@ -76,7 +76,7 @@
                 }
                 _result = MyEntity(_tmpPk,_tmpByteArray,_tmpNullableByteArray)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter.kt
index 6e7794e..e509e2e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter.kt
@@ -27,10 +27,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`foo`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 val _tmp: String = __fooConverter.toString(entity.foo)
                 statement.bindString(2, _tmp)
@@ -67,7 +67,7 @@
                 _tmpFoo = __fooConverter.fromString(_tmp)
                 _result = MyEntity(_tmpPk,_tmpFoo)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_composite.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_composite.kt
index 96566e6..d88a2e0 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_composite.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_composite.kt
@@ -25,10 +25,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`bar`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 val _tmp: Foo = FooBarConverter.toFoo(entity.bar)
                 val _tmp_1: String = FooBarConverter.toString(_tmp)
@@ -67,7 +67,7 @@
                 _tmpBar = FooBarConverter.fromFoo(_tmp_1)
                 _result = MyEntity(_tmpPk,_tmpBar)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_internalVisibility.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_internalVisibility.kt
index 0ba6f82..d5da42b 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_internalVisibility.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_internalVisibility.kt
@@ -27,10 +27,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`foo`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 val _tmp: String = __fooConverter.toString(entity.foo)
                 statement.bindString(2, _tmp)
@@ -67,7 +67,7 @@
                 _tmpFoo = __fooConverter.fromString(_tmp)
                 _result = MyEntity(_tmpPk,_tmpFoo)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_nullAware.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_nullAware.kt
index 0ea0420..5480240 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_nullAware.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_nullAware.kt
@@ -25,10 +25,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`foo`,`bar`) VALUES (?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 val _tmp: String? = FooBarConverter.toString(entity.foo)
                 if (_tmp == null) {
@@ -80,7 +80,7 @@
                 }
                 val _tmp_1: Foo? = FooBarConverter.fromString(_tmp)
                 if (_tmp_1 == null) {
-                    error("Expected non-null Foo, but it was null.")
+                    error("Expected NON-NULL 'Foo', but it was NULL.")
                 } else {
                     _tmpFoo = _tmp_1
                 }
@@ -99,13 +99,13 @@
                     _tmp_4 = FooBarConverter.fromFoo(_tmp_3)
                 }
                 if (_tmp_4 == null) {
-                    error("Expected non-null Bar, but it was null.")
+                    error("Expected NON-NULL 'Bar', but it was NULL.")
                 } else {
                     _tmpBar = _tmp_4
                 }
                 _result = MyEntity(_tmpPk,_tmpFoo,_tmpBar)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_provided.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_provided.kt
index 3895395..e6115de 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_provided.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_provided.kt
@@ -31,10 +31,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`foo`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 val _tmp: String = __fooConverter().toString(entity.foo)
                 statement.bindString(2, _tmp)
@@ -71,7 +71,7 @@
                 _tmpFoo = __fooConverter().fromString(_tmp)
                 _result = MyEntity(_tmpPk,_tmpFoo)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_embedded.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_embedded.kt
index b9a01bc..6a0e2c6 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_embedded.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_embedded.kt
@@ -26,10 +26,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`numberData`,`stringData`,`nullablenumberData`,`nullablestringData`) VALUES (?,?,?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 val _tmpFoo: Foo = entity.foo
                 statement.bindLong(2, _tmpFoo.numberData)
@@ -91,7 +91,7 @@
                 }
                 _result = MyEntity(_tmpPk,_tmpFoo,_tmpNullableFoo)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_enum.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_enum.kt
index a6f83a7..7dc5a23 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_enum.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_enum.kt
@@ -26,10 +26,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`enum`,`nullableEnum`) VALUES (?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, __Fruit_enumToString(entity.enum))
                 val _tmpNullableEnum: Fruit? = entity.nullableEnum
@@ -76,7 +76,7 @@
                 }
                 _result = MyEntity(_tmpPk,_tmpEnum,_tmpNullableEnum)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_internalVisibility.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_internalVisibility.kt
index db1f98c..3b6eb74 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_internalVisibility.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_internalVisibility.kt
@@ -26,10 +26,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`internalVal`,`internalVar`,`internalSetterVar`) VALUES (?,?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindLong(2, entity.internalVal)
                 statement.bindLong(3, entity.internalVar)
@@ -69,7 +69,7 @@
                 _result.internalVar = _cursor.getLong(_cursorIndexOfInternalVar)
                 _result.internalSetterVar = _cursor.getLong(_cursorIndexOfInternalSetterVar)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_otherModule.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_otherModule.kt
index 320a33b..138324c 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_otherModule.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_otherModule.kt
@@ -26,10 +26,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`primitive`,`string`,`nullableString`,`fieldString`,`nullableFieldString`,`variablePrimitive`,`variableString`,`variableNullableString`,`variableFieldString`,`variableNullableFieldString`) VALUES (?,?,?,?,?,?,?,?,?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindLong(2, entity.primitive)
                 statement.bindString(3, entity.string)
@@ -136,7 +136,7 @@
                         _cursor.getString(_cursorIndexOfVariableNullableFieldString)
                 }
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives.kt
index 520ecbb..45ad899 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives.kt
@@ -31,10 +31,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`int`,`short`,`byte`,`long`,`char`,`float`,`double`) VALUES (?,?,?,?,?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.int.toLong())
                 statement.bindLong(2, entity.short.toLong())
                 statement.bindLong(3, entity.byte.toLong())
@@ -88,7 +88,7 @@
                 _tmpDouble = _cursor.getDouble(_cursorIndexOfDouble)
                 _result = MyEntity(_tmpInt,_tmpShort,_tmpByte,_tmpLong,_tmpChar,_tmpFloat,_tmpDouble)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives_nullable.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives_nullable.kt
index 109df70..a970c59 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives_nullable.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives_nullable.kt
@@ -31,10 +31,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`int`,`short`,`byte`,`long`,`char`,`float`,`double`) VALUES (?,?,?,?,?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 val _tmpInt: Int? = entity.int
                 if (_tmpInt == null) {
                     statement.bindNull(1)
@@ -151,7 +151,7 @@
                 }
                 _result = MyEntity(_tmpInt,_tmpShort,_tmpByte,_tmpLong,_tmpChar,_tmpFloat,_tmpDouble)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_string.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_string.kt
index 213539a..982d042 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_string.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_string.kt
@@ -25,10 +25,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`string`,`nullableString`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindString(1, entity.string)
                 val _tmpNullableString: String? = entity.nullableString
                 if (_tmpNullableString == null) {
@@ -71,7 +71,7 @@
                 }
                 _result = MyEntity(_tmpString,_tmpNullableString)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_uuid.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_uuid.kt
index a4770df..27d03c4 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_uuid.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_uuid.kt
@@ -28,10 +28,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`uuid`,`nullableUuid`) VALUES (?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindBlob(2, convertUUIDToByte(entity.uuid))
                 val _tmpNullableUuid: UUID? = entity.nullableUuid
@@ -78,7 +78,7 @@
                 }
                 _result = MyEntity(_tmpPk,_tmpUuid,_tmpNullableUuid)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_valueClassConverter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_valueClassConverter.kt
index 6ea9026..51844206 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_valueClassConverter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_valueClassConverter.kt
@@ -29,15 +29,17 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`uuidData`,`nullableUuidData`,`nullableLongData`,`doubleNullableLongData`,`genericData`) VALUES (?,?,?,?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 val _data: Long = checkNotNull(entity.pk.data) {
-                    "Cannot bind nullable value of inline class to a NOT NULL column." }
+                    "Cannot bind NULLABLE value 'data' of inline class 'LongValueClass' to a NOT NULL column."
+                }
                 statement.bindLong(1, _data)
                 val _data_1: UUID = checkNotNull(entity.uuidData.data) {
-                    "Cannot bind nullable value of inline class to a NOT NULL column." }
+                    "Cannot bind NULLABLE value 'data' of inline class 'UUIDValueClass' to a NOT NULL column."
+                }
                 statement.bindBlob(2, convertUUIDToByte(_data_1))
                 val _tmpNullableUuidData: UUIDValueClass? = entity.nullableUuidData
                 val _data_2: UUID? = _tmpNullableUuidData?.data
@@ -47,7 +49,8 @@
                     statement.bindBlob(3, convertUUIDToByte(_data_2))
                 }
                 val _data_3: Long = checkNotNull(entity.nullableLongData.data) {
-                    "Cannot bind nullable value of inline class to a NOT NULL column." }
+                    "Cannot bind NULLABLE value 'data' of inline class 'NullableLongValueClass' to a NOT NULL column."
+                }
                 statement.bindLong(4, _data_3)
                 val _tmpDoubleNullableLongData: NullableLongValueClass? = entity.doubleNullableLongData
                 val _data_4: Long? = _tmpDoubleNullableLongData?.data
@@ -57,7 +60,8 @@
                     statement.bindLong(5, _data_4)
                 }
                 val _password: String = checkNotNull(entity.genericData.password) {
-                    "Cannot bind nullable value of inline class to a NOT NULL column." }
+                    "Cannot bind NULLABLE value 'password' of inline class 'GenericValueClass<String>' to a NOT NULL column."
+                }
                 statement.bindString(6, _password)
             }
         }
@@ -124,7 +128,7 @@
                 _result =
                     MyEntity(_tmpPk,_tmpUuidData,_tmpNullableUuidData,_tmpNullableLongData,_tmpDoubleNullableLongData,_tmpGenericData)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty.kt
index 6276d06..ef617b5 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty.kt
@@ -25,10 +25,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`variablePrimitive`,`variableString`,`variableNullableString`) VALUES (?,?,?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindLong(2, entity.variablePrimitive)
                 statement.bindString(3, entity.variableString)
@@ -77,7 +77,7 @@
                     _result.variableNullableString = _cursor.getString(_cursorIndexOfVariableNullableString)
                 }
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty_java.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty_java.kt
index 127eb24..a2eb766 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty_java.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty_java.kt
@@ -26,10 +26,10 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`mValue`,`mNullableValue`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.getValue())
                 val _tmpMNullableValue: String? = entity.getNullableValue()
                 if (_tmpMNullableValue == null) {
@@ -74,7 +74,7 @@
                 }
                 _result.setNullableValue(_tmpMNullableValue)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_guavaImmutableMap.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_guavaImmutableMap.kt
index 43a58d3..7e67d4e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_guavaImmutableMap.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_guavaImmutableMap.kt
@@ -43,7 +43,7 @@
                 _tmpArtistKey = _cursor.getString(_cursorIndexOfArtistKey)
                 _key = Song(_tmpSongId,_tmpArtistKey)
                 if (_cursor.isNull(_cursorIndexOfArtistId)) {
-                    error("Missing value for a key.")
+                    error("The column(s) of the map value object of type 'Artist' are NULL but the map's value type argument expect it to be NON-NULL")
                 }
                 val _value: Artist
                 val _tmpArtistId: String
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map.kt
index f42651e..6f80a49 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map.kt
@@ -45,7 +45,7 @@
                 _tmpArtistKey = _cursor.getString(_cursorIndexOfArtistKey)
                 _key = Song(_tmpSongId,_tmpArtistKey)
                 if (_cursor.isNull(_cursorIndexOfArtistId)) {
-                    error("Missing value for a key.")
+                    error("The column(s) of the map value object of type 'Artist' are NULL but the map's value type argument expect it to be NON-NULL")
                 }
                 val _value: Artist
                 val _tmpArtistId: String
@@ -119,7 +119,7 @@
                 _tmpArtistId = _cursor.getString(_cursorIndexOfArtistId)
                 _key = Artist(_tmpArtistId)
                 if (_cursor.isNull(_columnIndexOfSongCount)) {
-                    error("Missing value for a key.")
+                    error("The column(s) of the map value object of type 'Int' are NULL but the map's value type argument expect it to be NON-NULL")
                 }
                 val _value: Int
                 val _tmp: Int
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map_ambiguousIndexAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map_ambiguousIndexAdapter.kt
index 1c0720a..1f33090 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map_ambiguousIndexAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map_ambiguousIndexAdapter.kt
@@ -174,7 +174,7 @@
         }
         val _tmpName: String
         if (_cursorIndexOfName == -1) {
-            error("Missing column 'name' for a non null value.")
+            error("Missing value for a NON-NULL column 'name', found NULL value instead.")
         } else {
             _tmpName = cursor.getString(_cursorIndexOfName)
         }
@@ -201,7 +201,7 @@
         }
         val _tmpText: String
         if (_cursorIndexOfText == -1) {
-            error("Missing column 'text' for a non null value.")
+            error("Missing value for a NON-NULL column 'text', found NULL value instead.")
         } else {
             _tmpText = cursor.getString(_cursorIndexOfText)
         }
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt
index 63a7af9..2361e59 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt
@@ -29,7 +29,7 @@
             if (_cursor.moveToFirst()) {
                 _result = __entityCursorConverter_MyEntity(_cursor)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
index cf8c543..dee390f 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
@@ -60,11 +60,11 @@
                 _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
                 _tmpArtist = _collectionArtist.get(_tmpKey_1)
                 if (_tmpArtist == null) {
-                    error("Missing relationship item.")
+                    error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
                 }
                 _result = SongWithArtist(_tmpSong,_tmpArtist)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
             }
             return _result
         } finally {
@@ -102,7 +102,7 @@
                 _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
                 _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
             }
             return _result
         } finally {
@@ -140,7 +140,7 @@
                 _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
                 _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
index 7d2189f..a62f18e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
@@ -60,11 +60,11 @@
                 _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
                 _tmpArtist = _collectionArtist.get(_tmpKey_1)
                 if (_tmpArtist == null) {
-                    error("Missing relationship item.")
+                    error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
                 }
                 _result = SongWithArtist(_tmpSong,_tmpArtist)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
             }
             return _result
         } finally {
@@ -102,7 +102,7 @@
                 _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
                 _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
             }
             return _result
         } finally {
@@ -140,7 +140,7 @@
                 _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
                 _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
index c8e642f..56c0b4e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
@@ -61,11 +61,11 @@
                 _tmpKey_1 = ByteBuffer.wrap(_cursor.getBlob(_cursorIndexOfArtistKey))
                 _tmpArtist = _collectionArtist.get(_tmpKey_1)
                 if (_tmpArtist == null) {
-                    error("Missing relationship item.")
+                    error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
                 }
                 _result = SongWithArtist(_tmpSong,_tmpArtist)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
index 0a73c03..7a48aed 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
@@ -59,11 +59,11 @@
                 _tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
                 _tmpArtist = _collectionArtist.get(_tmpKey_1)
                 if (_tmpArtist == null) {
-                    error("Missing relationship item.")
+                    error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
                 }
                 _result = SongWithArtist(_tmpSong,_tmpArtist)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
             }
             return _result
         } finally {
@@ -101,7 +101,7 @@
                 _tmpSongsCollection = checkNotNull(_collectionSongs.get(_tmpKey_1))
                 _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
             }
             return _result
         } finally {
@@ -139,7 +139,7 @@
                 _tmpSongsCollection = checkNotNull(_collectionSongs.get(_tmpKey_1))
                 _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
index 4618226..9cb1cc6 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
@@ -79,7 +79,7 @@
                 }
                 _result = SongWithArtist(_tmpSong,_tmpArtist)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
             }
             return _result
         } finally {
@@ -117,7 +117,7 @@
                 _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
                 _result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
             }
             return _result
         } finally {
@@ -155,7 +155,7 @@
                 _tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
                 _result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
             } else {
-                error("Cursor was empty, but expected a single item.")
+                error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
             }
             return _result
         } finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx2.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx2.kt
index dd1a9ca..94244ec 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx2.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx2.kt
@@ -33,26 +33,26 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
             }
         }
         this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+            protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
             }
         }
         this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE OR ABORT `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
                 statement.bindLong(3, entity.pk.toLong())
@@ -60,18 +60,18 @@
         }
         this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
             EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
             }
         }, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
                 statement.bindLong(3, entity.pk.toLong())
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx3.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx3.kt
index bbab573..1e0ae5b 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx3.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx3.kt
@@ -33,26 +33,26 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
             }
         }
         this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+            protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
             }
         }
         this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE OR ABORT `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
                 statement.bindLong(3, entity.pk.toLong())
@@ -60,18 +60,18 @@
         }
         this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
             EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
             }
         }, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
                 statement.bindLong(3, entity.pk.toLong())
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_suspend.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_suspend.kt
index 3658985..8c4ef1a 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_suspend.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_suspend.kt
@@ -31,26 +31,26 @@
     init {
         this.__db = __db
         this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT OR ABORT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
             }
         }
         this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+            protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
             }
         }
         this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE OR ABORT `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
                 statement.bindLong(3, entity.pk.toLong())
@@ -58,18 +58,18 @@
         }
         this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
             EntityInsertionAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "INSERT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
             }
         }, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
-            public override fun createQuery(): String =
+            protected override fun createQuery(): String =
                 "UPDATE `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
 
-            public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+            protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
                 statement.bindLong(1, entity.pk.toLong())
                 statement.bindString(2, entity.other)
                 statement.bindLong(3, entity.pk.toLong())
diff --git a/settings.gradle b/settings.gradle
index 34dec2f..5e4699c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -906,6 +906,7 @@
 includeProject(":privacysandbox:plugins:plugins-privacysandbox-library", [BuildType.MAIN])
 includeProject(":privacysandbox:sdkruntime:sdkruntime-client", [BuildType.MAIN])
 includeProject(":privacysandbox:sdkruntime:sdkruntime-core", [BuildType.MAIN])
+includeProject(":privacysandbox:sdkruntime:test-sdks:current", [BuildType.MAIN])
 includeProject(":privacysandbox:tools:tools", [BuildType.MAIN])
 includeProject(":privacysandbox:tools:tools-apicompiler", [BuildType.MAIN])
 includeProject(":privacysandbox:tools:tools-apigenerator", [BuildType.MAIN])
diff --git a/slidingpanelayout/slidingpanelayout/build.gradle b/slidingpanelayout/slidingpanelayout/build.gradle
index 18bea17..58cbeb8 100644
--- a/slidingpanelayout/slidingpanelayout/build.gradle
+++ b/slidingpanelayout/slidingpanelayout/build.gradle
@@ -14,7 +14,6 @@
     implementation("androidx.transition:transition:1.4.1")
 
     androidTestImplementation(libs.testExtJunit)
-    androidTestImplementation(libs.testRules)
     androidTestImplementation(libs.testRunner)
     androidTestImplementation(libs.espressoCore, excludes.espresso)
     androidTestImplementation(libs.kotlinStdlib)
diff --git a/slidingpanelayout/slidingpanelayout/lint-baseline.xml b/slidingpanelayout/slidingpanelayout/lint-baseline.xml
deleted file mode 100644
index 1557792..0000000
--- a/slidingpanelayout/slidingpanelayout/lint-baseline.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-beta05" type="baseline" client="gradle" dependencies="false" name="AGP (8.1.0-beta05)" variant="all" version="8.1.0-beta05">
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 28; however, the containing class androidx.slidingpanelayout.widget.SlidingPaneLayout is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            if (panel.getAccessibilityPaneTitle() != null) {"
-        errorLine2="                      ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 28; however, the containing class androidx.slidingpanelayout.widget.SlidingPaneLayout is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="                        panel.getAccessibilityPaneTitle().toString());"
-        errorLine2="                              ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 19; however, the containing class androidx.slidingpanelayout.widget.SlidingPaneLayout is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            event.setContentChangeTypes(contentType);"
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java"/>
-    </issue>
-
-    <issue
-        id="ClassVerificationFailure"
-        message="This call references a method added in API level 16; however, the containing class androidx.slidingpanelayout.widget.SlidingPaneLayout is reachable from earlier API levels and will fail run-time class verification."
-        errorLine1="            panel.performAccessibilityAction("
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java"/>
-    </issue>
-
-</issues>
diff --git a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutAccessibilityTest.kt b/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutAccessibilityTest.kt
deleted file mode 100644
index af31cec..0000000
--- a/slidingpanelayout/slidingpanelayout/src/androidTest/java/androidx/slidingpanelayout/widget/SlidingPaneLayoutAccessibilityTest.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.slidingpanelayout.widget
-
-import android.app.UiAutomation
-import android.os.Build
-import android.view.View
-import android.view.accessibility.AccessibilityEvent
-import android.widget.TextView
-import androidx.core.view.ViewCompat
-import androidx.slidingpanelayout.test.R
-import androidx.slidingpanelayout.widget.helpers.TestActivity
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
-import androidx.test.filters.SdkSuppress
-import androidx.test.platform.app.InstrumentationRegistry
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@MediumTest
-@SdkSuppress(minSdkVersion = 19)
-class SlidingPaneLayoutAccessibilityTest {
-
-    @Suppress("DEPRECATION")
-    @get:Rule
-    val mActivityTestRule = androidx.test.rule.ActivityTestRule(
-        TestActivity::class.java
-    )
-
-    private val timeout = 5000L
-
-    private lateinit var uiAutomation: UiAutomation
-    private lateinit var slidingPaneLayout: SlidingPaneLayout
-
-    private lateinit var listPane: TextView
-    private lateinit var detailPane: TextView
-
-    @Before
-    fun setup() {
-        val instrumentation = InstrumentationRegistry.getInstrumentation()
-        uiAutomation = instrumentation.uiAutomation
-
-        val activity = mActivityTestRule.activity
-        mActivityTestRule.runOnUiThread {
-            slidingPaneLayout = activity.findViewById(R.id.sliding_pane_layout) as SlidingPaneLayout
-            listPane = activity.findViewById(R.id.list_pane) as TextView
-            detailPane = activity.findViewById(R.id.detail_pane) as TextView
-            // On KitKat, some delegate methods aren't called for non-important views
-            ViewCompat.setImportantForAccessibility(
-                slidingPaneLayout, View.IMPORTANT_FOR_ACCESSIBILITY_YES)
-        }
-    }
-
-    @Test
-    fun testPaneOpening() {
-        ViewCompat.setAccessibilityPaneTitle(detailPane, "Detail Pane")
-        ViewCompat.setAccessibilityPaneTitle(listPane, "List Pane")
-        mActivityTestRule.runOnUiThread {
-            detailPane.visibility = View.INVISIBLE
-            detailPane.viewTreeObserver.dispatchOnGlobalLayout()
-        }
-        uiAutomation.executeAndWaitForEvent(
-            {
-                try {
-                    mActivityTestRule.runOnUiThread {
-                        slidingPaneLayout.openPane()
-                    }
-                } catch (throwable: Throwable) {
-                    throwable.printStackTrace()
-                }
-            },
-            { event ->
-                val isWindowStateChanged =
-                    event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
-                val isPaneTitle: Int = (event.contentChangeTypes
-                    and AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED)
-                (isWindowStateChanged && isPaneTitle != 0)
-            }, timeout
-        )
-    }
-
-    @Test
-    fun testPaneClosing() {
-        ViewCompat.setAccessibilityPaneTitle(detailPane, "Detail Pane")
-        ViewCompat.setAccessibilityPaneTitle(listPane, "List Pane")
-        mActivityTestRule.runOnUiThread {
-            detailPane.visibility = View.INVISIBLE
-            detailPane.viewTreeObserver.dispatchOnGlobalLayout()
-            slidingPaneLayout.openPane()
-            detailPane.visibility = View.VISIBLE
-            if (Build.VERSION.SDK_INT < 28) {
-                detailPane.viewTreeObserver.dispatchOnGlobalLayout()
-            }
-        }
-        uiAutomation.executeAndWaitForEvent(
-            {
-                try {
-                    mActivityTestRule.runOnUiThread {
-                        slidingPaneLayout.closePane()
-                    }
-                } catch (throwable: Throwable) {
-                    throwable.printStackTrace()
-                }
-            },
-            { event ->
-                val isWindowStateChanged =
-                    event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
-                val isPaneTitle: Int = (event.contentChangeTypes
-                    and AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)
-                (isWindowStateChanged && isPaneTitle != 0)
-            }, timeout
-        )
-    }
-}
diff --git a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
index a8533c2..4c826d2 100644
--- a/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
+++ b/slidingpanelayout/slidingpanelayout/src/main/java/androidx/slidingpanelayout/widget/SlidingPaneLayout.java
@@ -503,58 +503,14 @@
         for (PanelSlideListener listener : mPanelSlideListeners) {
             listener.onPanelOpened(panel);
         }
-        sendAccessibilityPaneTitleEvent(panel);
-        sendChangedFocusAccessibilityEvents(panel,
-                AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED);
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
     }
 
     void dispatchOnPanelClosed(@NonNull View panel) {
         for (PanelSlideListener listener : mPanelSlideListeners) {
             listener.onPanelClosed(panel);
         }
-        View parentPanel = getChildAt(0);
-        sendAccessibilityPaneTitleEvent(parentPanel);
-        sendChangedFocusAccessibilityEvents(parentPanel,
-                AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED);
-    }
-
-    /**
-     * Sets the Accessibility title when the API is above API 28. This logic is required due to the
-     * opening and closing drawer logic and the title must be updated for each open and close.
-     * @param panel Panel with the current fovus
-     */
-    private void sendAccessibilityPaneTitleEvent(final View panel) {
-        if (panel == null) return;
-
-        if (Build.VERSION.SDK_INT >= 28) {
-            if (panel.getAccessibilityPaneTitle() != null) {
-                ViewCompat.setAccessibilityPaneTitle(panel,
-                        panel.getAccessibilityPaneTitle().toString());
-            }
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    private void sendChangedFocusAccessibilityEvents(final View panel, int contentType) {
-        if (panel == null) return;
-
-        if (Build.VERSION.SDK_INT >= 19) {
-            AccessibilityEvent event = AccessibilityEvent.obtain(
-                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-            event.setContentChangeTypes(contentType);
-            sendAccessibilityEventUnchecked(event);
-        } else {
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-        }
-
-        // If a view can slide, the previous view will be completely hidden
-        // This sets the focus for the root view of the child when shown.
-        // TODO(224450896): We should not force accessibility focus. Remove when screen reader
-        //  behavior around panes is defined.
-        if (mCanSlide && Build.VERSION.SDK_INT >= 16) {
-            panel.performAccessibilityAction(
-                    AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS, null);
-        }
+        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
     }
 
     void updateObscuredViewsVisibility(View panel) {
diff --git a/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt b/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt
index 0bc25f4..01a897c 100644
--- a/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt
+++ b/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt
@@ -25,6 +25,7 @@
 import androidx.benchmark.macro.Metric
 import androidx.benchmark.macro.StartupMode
 import androidx.benchmark.macro.StartupTimingMetric
+import androidx.benchmark.macro.TraceSectionMetric
 import androidx.benchmark.macro.isSupportedWithVmSettings
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 
@@ -67,7 +68,11 @@
  */
 @OptIn(ExperimentalMetricApi::class)
 fun getStartupMetrics() =
-    listOf(StartupTimingMetric(), MemoryUsageMetric(MemoryUsageMetric.Mode.Last))
+    listOf(
+        StartupTimingMetric(),
+        TraceSectionMetric("StartupTracingInitializer"),
+        MemoryUsageMetric(MemoryUsageMetric.Mode.Last)
+    )
 
 fun MacrobenchmarkRule.measureStartup(
     compilationMode: CompilationMode,
diff --git a/tracing/tracing-perfetto/src/main/AndroidManifest.xml b/tracing/tracing-perfetto/src/main/AndroidManifest.xml
index 7402b3a..c955790 100644
--- a/tracing/tracing-perfetto/src/main/AndroidManifest.xml
+++ b/tracing/tracing-perfetto/src/main/AndroidManifest.xml
@@ -32,8 +32,6 @@
             </intent-filter>
         </receiver>
 
-        <!-- TODO(283953019): enable when feature complete (i.e. after measuring perf impact) -->
-        <!--
         <provider
             android:name="androidx.startup.InitializationProvider"
             android:authorities="${applicationId}.androidx-startup"
@@ -43,6 +41,12 @@
                 android:name="androidx.tracing.perfetto.StartupTracingInitializer"
                 android:value="androidx.startup" />
         </provider>
-        -->
+        <receiver
+            android:name="androidx.tracing.perfetto.StartupTracingConfigStoreIsEnabledGate"
+            android:enabled="false"
+            android:exported="false"
+            android:directBootAware="false"
+            tools:targetApi="n">
+        </receiver>
     </application>
 </manifest>
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingConfig.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingConfig.kt
index e83611c..fd34d99 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingConfig.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingConfig.kt
@@ -16,10 +16,13 @@
 
 package androidx.tracing.perfetto
 
-import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED
 import java.io.File
-import java.io.Writer
 import java.util.Properties
 
 /**
@@ -28,10 +31,39 @@
  * @param libFilePath Path to the optionally sideloaded `libtracing_perfetto.so` file
  * @param isPersistent Determines whether tracing should remain enabled (sticky) between app runs
  */
-@RestrictTo(LIBRARY_GROUP)
 internal data class StartupTracingConfig(val libFilePath: String?, val isPersistent: Boolean)
 
-@RestrictTo(LIBRARY_GROUP)
+/**
+ * Hack used by [StartupTracingConfigStore] to perform a fast check whether there is
+ * a [StartupTracingConfig] present. Relies on [PackageManager.getComponentEnabledSetting] and a
+ * dummy [BroadcastReceiver] component.
+ */
+private abstract class StartupTracingConfigStoreIsEnabledGate : BroadcastReceiver() {
+    companion object {
+        fun enable(context: Context) = setEnabledSetting(context, true)
+
+        fun disable(context: Context) = setEnabledSetting(context, false)
+
+        private fun setEnabledSetting(context: Context, enabled: Boolean) {
+            context.packageManager.setComponentEnabledSetting(
+                context.componentName,
+                if (enabled) COMPONENT_ENABLED_STATE_ENABLED else COMPONENT_ENABLED_STATE_DISABLED,
+                PackageManager.DONT_KILL_APP
+            )
+        }
+
+        fun isEnabled(context: Context): Boolean =
+            context.packageManager.getComponentEnabledSetting(context.componentName) ==
+                COMPONENT_ENABLED_STATE_ENABLED
+
+        private val Context.componentName
+            get() = ComponentName(
+                this,
+                StartupTracingConfigStoreIsEnabledGate::class.java.name
+            )
+    }
+}
+
 internal object StartupTracingConfigStore {
     private const val KEY_IS_PERSISTENT = "isPersistent"
     private const val KEY_LIB_FILE_PATH = "libtracingPerfettoFilePath"
@@ -41,9 +73,12 @@
         File("/sdcard/Android/media/$packageName/$STARTUP_CONFIG_FILE_NAME")
 
     /** Loads the config */
-    fun load(packageName: String): StartupTracingConfig? {
+    fun load(context: Context): StartupTracingConfig? {
+        // use the fast-check-gate value
+        if (!StartupTracingConfigStoreIsEnabledGate.isEnabled(context)) return null
+
         // read the config from file
-        val propertiesFile = startupConfigFileForPackageName(packageName)
+        val propertiesFile = startupConfigFileForPackageName(context.packageName)
         if (!propertiesFile.exists()) return null
         val properties = Properties()
         propertiesFile.reader().use { properties.load(it) }
@@ -54,24 +89,21 @@
     }
 
     /** Stores the config */
-    fun StartupTracingConfig.store(packageName: String): Unit =
-        startupConfigFileForPackageName(packageName)
+    fun StartupTracingConfig.store(context: Context) {
+        startupConfigFileForPackageName(context.packageName)
             .bufferedWriter()
-            .use { store(it) }
-
-    /**
-     * Stores the config as a [Properties] string
-     *
-     * The caller is responsible for closing the passed-in [Writer]
-     */
-    private fun StartupTracingConfig.store(writer: Writer) =
-        Properties().also {
-            it.setProperty(KEY_LIB_FILE_PATH, libFilePath)
-            it.setProperty(KEY_IS_PERSISTENT, isPersistent.toString())
-        }.store(writer, null)
+            .use { writer ->
+                Properties().also {
+                    it.setProperty(KEY_LIB_FILE_PATH, libFilePath)
+                    it.setProperty(KEY_IS_PERSISTENT, isPersistent.toString())
+                }.store(writer, null)
+            }
+        StartupTracingConfigStoreIsEnabledGate.enable(context) // update the fast-check-gate value
+    }
 
     /** Deletes the config */
-    fun clear(packageName: String) {
-        startupConfigFileForPackageName(packageName).delete()
+    fun clear(context: Context) {
+        StartupTracingConfigStoreIsEnabledGate.disable(context) // update the fast-check-gate value
+        startupConfigFileForPackageName(context.packageName).delete()
     }
 }
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingInitializer.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingInitializer.kt
index ab2d6fd..ee2ea0d 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingInitializer.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingInitializer.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.os.Build
+import android.os.StrictMode
 import android.util.Log
 import androidx.startup.Initializer
 import androidx.tracing.perfetto.internal.handshake.protocol.Response
@@ -33,27 +34,38 @@
         // TODO(234351579): Support API < 30
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return
 
-        // read startup tracing config file if present
-        val packageName = context.applicationInfo.packageName
-        val config = StartupTracingConfigStore.load(packageName)
-            ?: return // early exit if no config is found
+        suppressStrictModeDiskWrites {
+            // read startup tracing config if present
+            val config = StartupTracingConfigStore.load(context)
+                ?: return // early exit if no config is found
 
-        // delete config file if not meant to be preserved between runs
-        if (!config.isPersistent) StartupTracingConfigStore.clear(packageName)
+            // delete config if not meant to be preserved between runs
+            if (!config.isPersistent) StartupTracingConfigStore.clear(context)
 
-        // enable tracing
-        val libFilePath = config.libFilePath
-        val enableTracingResponse =
-            if (libFilePath == null) PerfettoSdkTrace.enable()
-            else PerfettoSdkTrace.enable(File(libFilePath), context)
+            // enable tracing
+            val libFilePath = config.libFilePath
+            val enableTracingResponse =
+                if (libFilePath == null) PerfettoSdkTrace.enable()
+                else PerfettoSdkTrace.enable(File(libFilePath), context)
 
-        // log the result for debuggability
-        Log.d(TAG, "${Response::class.java.name}: { " +
-            "resultCode: ${enableTracingResponse.resultCode}, " +
-            "message: ${enableTracingResponse.message}, " +
-            "requiredVersion: ${enableTracingResponse.requiredVersion} " +
-            "}")
+            // log the result for debuggability
+            Log.d(TAG, "${Response::class.java.name}: { " +
+                "resultCode: ${enableTracingResponse.resultCode}, " +
+                "message: ${enableTracingResponse.message}, " +
+                "requiredVersion: ${enableTracingResponse.requiredVersion} " +
+                "}")
+        }
     }
 
     override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
+
+    // TODO(245426369): test in TrivialStartupTracingBenchmark
+    private inline fun <R> suppressStrictModeDiskWrites(block: () -> R): R {
+        val oldPolicy = StrictMode.allowThreadDiskWrites()
+        try {
+            return block()
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy)
+        }
+    }
 }
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt
index 2bfa12e..6f45b92 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt
@@ -134,13 +134,13 @@
                 RESULT_CODE_ERROR_OTHER,
                 "Cannot set up cold start tracing without a Context instance."
             )
-            config.store(context.applicationInfo.packageName)
+            config.store(context)
         }
     }
 
     private fun disableTracingColdStart(context: Context?): Response = when {
         context != null -> {
-            StartupTracingConfigStore.clear(context.applicationInfo.packageName)
+            StartupTracingConfigStore.clear(context)
             Response(RESULT_CODE_SUCCESS)
         }
         else ->
diff --git a/tv/samples/src/main/java/androidx/tv/samples/NavigationDrawerSamples.kt b/tv/samples/src/main/java/androidx/tv/samples/NavigationDrawerSamples.kt
index 345adc6..dc061ec 100644
--- a/tv/samples/src/main/java/androidx/tv/samples/NavigationDrawerSamples.kt
+++ b/tv/samples/src/main/java/androidx/tv/samples/NavigationDrawerSamples.kt
@@ -32,6 +32,7 @@
 import androidx.compose.material3.Button
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.dp
@@ -80,7 +81,7 @@
 @OptIn(ExperimentalTvMaterial3Api::class)
 @Sampled
 @Composable
-fun SampleModalNavigationDrawer() {
+fun SampleModalNavigationDrawerWithSolidScrim() {
     val navigationRow: @Composable (drawerValue: DrawerValue, color: Color, text: String) -> Unit =
         { drawerValue, color, text ->
             Row(Modifier.padding(10.dp).focusable()) {
@@ -112,3 +113,40 @@
         }
     }
 }
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@Sampled
+@Composable
+fun SampleModalNavigationDrawerWithGradientScrim() {
+    val navigationRow: @Composable (drawerValue: DrawerValue, color: Color, text: String) -> Unit =
+        { drawerValue, color, text ->
+            Row(Modifier.padding(10.dp).focusable()) {
+                Box(Modifier.size(50.dp).background(color).padding(end = 20.dp))
+                AnimatedVisibility(visible = drawerValue == DrawerValue.Open) {
+                    Text(
+                        text = text,
+                        softWrap = false,
+                        modifier = Modifier.padding(15.dp).width(50.dp),
+                        textAlign = TextAlign.Center
+                    )
+                }
+            }
+        }
+
+    androidx.tv.material3.ModalNavigationDrawer(
+        drawerContent = {
+            Column(Modifier.fillMaxHeight()) {
+                navigationRow(it, Color.Red, "Red")
+                navigationRow(it, Color.Blue, "Blue")
+                navigationRow(it, Color.Yellow, "Yellow")
+            }
+        },
+        scrimBrush = Brush.horizontalGradient(listOf(Color.DarkGray, Color.Transparent))
+    ) {
+        Button(modifier = Modifier
+            .height(100.dp)
+            .fillMaxWidth(), onClick = {}) {
+            Text("BUTTON")
+        }
+    }
+}
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt
index b95b687..5cf5964 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt
@@ -127,7 +127,7 @@
             ),
         prefetchState = state.prefetchState,
         measurePolicy = measurePolicy,
-        itemProvider = itemProvider
+        itemProvider = { itemProvider }
     )
 }
 
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt
index 224af43..34254cc 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt
@@ -131,7 +131,7 @@
             ),
         prefetchState = state.prefetchState,
         measurePolicy = measurePolicy,
-        itemProvider = itemProvider
+        itemProvider = { itemProvider }
     )
 }
 
diff --git a/tv/tv-material/api/current.txt b/tv/tv-material/api/current.txt
index f1485a9..3dca4bb 100644
--- a/tv/tv-material/api/current.txt
+++ b/tv/tv-material/api/current.txt
@@ -578,7 +578,7 @@
   }
 
   public final class NavigationDrawerKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional long scrimColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional androidx.compose.ui.graphics.Brush scrimBrush, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static androidx.tv.material3.DrawerState rememberDrawerState(androidx.tv.material3.DrawerValue initialValue);
   }
diff --git a/tv/tv-material/api/restricted_current.txt b/tv/tv-material/api/restricted_current.txt
index f1485a9..3dca4bb 100644
--- a/tv/tv-material/api/restricted_current.txt
+++ b/tv/tv-material/api/restricted_current.txt
@@ -578,7 +578,7 @@
   }
 
   public final class NavigationDrawerKt {
-    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional long scrimColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional androidx.compose.ui.graphics.Brush scrimBrush, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static androidx.tv.material3.DrawerState rememberDrawerState(androidx.tv.material3.DrawerValue initialValue);
   }
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
index ac34cff..a3f7e6d 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
@@ -40,7 +40,8 @@
 import androidx.compose.ui.focus.FocusState
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.focus.onFocusChanged
-import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.SolidColor
 import androidx.compose.ui.layout.onSizeChanged
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.Dp
@@ -59,7 +60,8 @@
  * layout grid.
  *
  * Example:
- * @sample androidx.tv.samples.SampleModalNavigationDrawer
+ * @sample androidx.tv.samples.SampleModalNavigationDrawerWithSolidScrim
+ * @sample androidx.tv.samples.SampleModalNavigationDrawerWithGradientScrim
  *
  * @param drawerContent Content that needs to be displayed on the drawer based on whether the drawer
  * is [DrawerValue.Open] or [DrawerValue.Closed].
@@ -72,7 +74,7 @@
  *
  * @param modifier the [Modifier] to be applied to this drawer
  * @param drawerState state of the drawer
- * @param scrimColor color of the scrim that obscures content when the drawer is open
+ * @param scrimBrush brush to paint the scrim that obscures content when the drawer is open
  * @param content content of the rest of the UI
  */
 @ExperimentalTvMaterial3Api
@@ -81,7 +83,7 @@
     drawerContent: @Composable (DrawerValue) -> Unit,
     modifier: Modifier = Modifier,
     drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
-    scrimColor: Color = LocalColorScheme.current.scrim.copy(alpha = 0.5f),
+    scrimBrush: Brush = SolidColor(LocalColorScheme.current.scrim.copy(alpha = 0.5f)),
     content: @Composable () -> Unit
 ) {
     val localDensity = LocalDensity.current
@@ -113,14 +115,14 @@
             content = drawerContent
         )
 
+        if (drawerState.currentValue == DrawerValue.Open) {
+            // Scrim
+            Canvas(Modifier.fillMaxSize()) {
+                drawRect(scrimBrush)
+            }
+        }
         Box(Modifier.padding(start = closedDrawerWidth.value ?: ClosedDrawerWidth.dp)) {
             content()
-            if (drawerState.currentValue == DrawerValue.Open) {
-                // Scrim
-                Canvas(Modifier.fillMaxSize()) {
-                    drawRect(scrimColor)
-                }
-            }
         }
     }
 }
diff --git a/tvprovider/tvprovider/api/api_lint.ignore b/tvprovider/tvprovider/api/api_lint.ignore
index 60a676a..16230a6 100644
--- a/tvprovider/tvprovider/api/api_lint.ignore
+++ b/tvprovider/tvprovider/api/api_lint.ignore
@@ -81,13 +81,9 @@
     Public class androidx.tvprovider.media.tv.WatchNextProgram stripped of unavailable superclass androidx.tvprovider.media.tv.BasePreviewProgram
 
 
-IntentName: androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_COUNT:
+IntentName: androidx.tvprovider.media.tv.TvContractCompat.PreviewProgramColumns#COLUMN_INTERACTION_COUNT:
     Intent action constant name must be ACTION_FOO: COLUMN_INTERACTION_COUNT
-IntentName: androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_TYPE:
-    Intent action constant name must be ACTION_FOO: COLUMN_INTERACTION_TYPE
-IntentName: androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms#COLUMN_INTERACTION_COUNT:
-    Intent action constant name must be ACTION_FOO: COLUMN_INTERACTION_COUNT
-IntentName: androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms#COLUMN_INTERACTION_TYPE:
+IntentName: androidx.tvprovider.media.tv.TvContractCompat.PreviewProgramColumns#COLUMN_INTERACTION_TYPE:
     Intent action constant name must be ACTION_FOO: COLUMN_INTERACTION_TYPE
 
 
diff --git a/tvprovider/tvprovider/api/current.txt b/tvprovider/tvprovider/api/current.txt
index c82fb20..1ca7bb2 100644
--- a/tvprovider/tvprovider/api/current.txt
+++ b/tvprovider/tvprovider/api/current.txt
@@ -195,6 +195,7 @@
     method public boolean isSearchable();
     method public boolean isTransient();
     method public android.content.ContentValues! toContentValues();
+    field public static final String![] PROJECTION;
   }
 
   public static final class PreviewProgram.Builder {
@@ -458,7 +459,7 @@
     field public static final String CONTENT_DIRECTORY = "logo";
   }
 
-  public static final class TvContractCompat.PreviewPrograms implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns {
+  public static interface TvContractCompat.PreviewProgramColumns {
     field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
     field public static final int ASPECT_RATIO_1_1 = 3; // 0x3
     field public static final int ASPECT_RATIO_2_3 = 4; // 0x4
@@ -472,62 +473,33 @@
     field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
     field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
     field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
-    field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final String COLUMN_AUTHOR = "author";
     field public static final String COLUMN_AVAILABILITY = "availability";
     field public static final String COLUMN_BROWSABLE = "browsable";
-    field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final String COLUMN_CHANNEL_ID = "channel_id";
     field public static final String COLUMN_CONTENT_ID = "content_id";
-    field public static final String COLUMN_CONTENT_RATING = "content_rating";
     field public static final String COLUMN_DURATION_MILLIS = "duration_millis";
     field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
-    field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
-    field public static final String COLUMN_EPISODE_TITLE = "episode_title";
     field public static final String COLUMN_GENRE = "genre";
     field public static final String COLUMN_INTENT_URI = "intent_uri";
     field public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
     field public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
-    field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
-    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
-    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
-    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
-    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
     field public static final String COLUMN_ITEM_COUNT = "item_count";
     field public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
     field public static final String COLUMN_LIVE = "live";
     field public static final String COLUMN_LOGO_CONTENT_DESCRIPTION = "logo_content_description";
     field public static final String COLUMN_LOGO_URI = "logo_uri";
-    field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final String COLUMN_OFFER_PRICE = "offer_price";
     field public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-    field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
     field public static final String COLUMN_PREVIEW_AUDIO_URI = "preview_audio_uri";
     field public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
     field public static final String COLUMN_RELEASE_DATE = "release_date";
-    field public static final String COLUMN_REVIEW_RATING = "review_rating";
-    field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-    field public static final String COLUMN_SEARCHABLE = "searchable";
-    field public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
-    field public static final String COLUMN_SEASON_TITLE = "season_title";
-    field public static final String COLUMN_SERIES_ID = "series_id";
-    field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
     field public static final String COLUMN_STARTING_PRICE = "starting_price";
     field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
     field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
-    field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
-    field public static final String COLUMN_TITLE = "title";
     field public static final String COLUMN_TRANSIENT = "transient";
     field public static final String COLUMN_TV_SERIES_ITEM_TYPE = "tv_series_item_type";
     field public static final String COLUMN_TYPE = "type";
-    field public static final String COLUMN_VERSION_NUMBER = "version_number";
-    field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
-    field public static final String COLUMN_VIDEO_WIDTH = "video_width";
-    field public static final String COLUMN_WEIGHT = "weight";
-    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
-    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
-    field public static final android.net.Uri! CONTENT_URI;
     field public static final int INTERACTION_TYPE_FANS = 3; // 0x3
     field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2
     field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4
@@ -535,9 +507,6 @@
     field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5
     field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6
     field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0
-    field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
-    field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
-    field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
     field public static final int TV_SERIES_ITEM_TYPE_CHAPTER = 1; // 0x1
     field public static final int TV_SERIES_ITEM_TYPE_EPISODE = 0; // 0x0
     field public static final int TYPE_ALBUM = 8; // 0x8
@@ -555,6 +524,41 @@
     field public static final int TYPE_TV_SERIES = 1; // 0x1
   }
 
+  public static final class TvContractCompat.PreviewPrograms implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns androidx.tvprovider.media.tv.TvContractCompat.PreviewProgramColumns {
+    field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+    field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+    field public static final String COLUMN_CHANNEL_ID = "channel_id";
+    field public static final String COLUMN_CONTENT_RATING = "content_rating";
+    field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+    field public static final String COLUMN_EPISODE_TITLE = "episode_title";
+    field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+    field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+    field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+    field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final String COLUMN_REVIEW_RATING = "review_rating";
+    field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+    field public static final String COLUMN_SEARCHABLE = "searchable";
+    field public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+    field public static final String COLUMN_SEASON_TITLE = "season_title";
+    field public static final String COLUMN_SERIES_ID = "series_id";
+    field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+    field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+    field public static final String COLUMN_TITLE = "title";
+    field public static final String COLUMN_VERSION_NUMBER = "version_number";
+    field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+    field public static final String COLUMN_VIDEO_WIDTH = "video_width";
+    field public static final String COLUMN_WEIGHT = "weight";
+    field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
+    field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
+    field public static final android.net.Uri! CONTENT_URI;
+    field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
+    field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
+    field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
+  }
+
   public static final class TvContractCompat.Programs implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns {
     field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
     field public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
@@ -662,54 +666,20 @@
     field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
   }
 
-  public static final class TvContractCompat.WatchNextPrograms implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns {
-    field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
-    field public static final int ASPECT_RATIO_1_1 = 3; // 0x3
-    field public static final int ASPECT_RATIO_2_3 = 4; // 0x4
-    field public static final int ASPECT_RATIO_3_2 = 1; // 0x1
-    field public static final int ASPECT_RATIO_3_4 = 6; // 0x6
-    field public static final int ASPECT_RATIO_4_3 = 2; // 0x2
-    field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
-    field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
-    field public static final int AVAILABILITY_FREE = 4; // 0x4
-    field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
-    field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
-    field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
-    field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
+  public static final class TvContractCompat.WatchNextPrograms implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns androidx.tvprovider.media.tv.TvContractCompat.PreviewProgramColumns {
     field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
-    field public static final String COLUMN_AUTHOR = "author";
-    field public static final String COLUMN_AVAILABILITY = "availability";
-    field public static final String COLUMN_BROWSABLE = "browsable";
     field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
-    field public static final String COLUMN_CONTENT_ID = "content_id";
     field public static final String COLUMN_CONTENT_RATING = "content_rating";
-    field public static final String COLUMN_DURATION_MILLIS = "duration_millis";
-    field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
     field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
     field public static final String COLUMN_EPISODE_TITLE = "episode_title";
-    field public static final String COLUMN_GENRE = "genre";
-    field public static final String COLUMN_INTENT_URI = "intent_uri";
-    field public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
-    field public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
     field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
     field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
     field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
     field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
     field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
-    field public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
-    field public static final String COLUMN_ITEM_COUNT = "item_count";
     field public static final String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
-    field public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
-    field public static final String COLUMN_LIVE = "live";
-    field public static final String COLUMN_LOGO_CONTENT_DESCRIPTION = "logo_content_description";
-    field public static final String COLUMN_LOGO_URI = "logo_uri";
     field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
-    field public static final String COLUMN_OFFER_PRICE = "offer_price";
-    field public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
     field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
-    field public static final String COLUMN_PREVIEW_AUDIO_URI = "preview_audio_uri";
-    field public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
-    field public static final String COLUMN_RELEASE_DATE = "release_date";
     field public static final String COLUMN_REVIEW_RATING = "review_rating";
     field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
     field public static final String COLUMN_SEARCHABLE = "searchable";
@@ -717,14 +687,8 @@
     field public static final String COLUMN_SEASON_TITLE = "season_title";
     field public static final String COLUMN_SERIES_ID = "series_id";
     field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
-    field public static final String COLUMN_STARTING_PRICE = "starting_price";
-    field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
-    field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
     field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
     field public static final String COLUMN_TITLE = "title";
-    field public static final String COLUMN_TRANSIENT = "transient";
-    field public static final String COLUMN_TV_SERIES_ITEM_TYPE = "tv_series_item_type";
-    field public static final String COLUMN_TYPE = "type";
     field public static final String COLUMN_VERSION_NUMBER = "version_number";
     field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
     field public static final String COLUMN_VIDEO_WIDTH = "video_width";
@@ -732,31 +696,9 @@
     field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
     field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
     field public static final android.net.Uri! CONTENT_URI;
-    field public static final int INTERACTION_TYPE_FANS = 3; // 0x3
-    field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2
-    field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4
-    field public static final int INTERACTION_TYPE_LISTENS = 1; // 0x1
-    field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5
-    field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6
-    field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0
     field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
     field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
     field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
-    field public static final int TV_SERIES_ITEM_TYPE_CHAPTER = 1; // 0x1
-    field public static final int TV_SERIES_ITEM_TYPE_EPISODE = 0; // 0x0
-    field public static final int TYPE_ALBUM = 8; // 0x8
-    field public static final int TYPE_ARTIST = 9; // 0x9
-    field public static final int TYPE_CHANNEL = 6; // 0x6
-    field public static final int TYPE_CLIP = 4; // 0x4
-    field public static final int TYPE_EVENT = 5; // 0x5
-    field public static final int TYPE_GAME = 12; // 0xc
-    field public static final int TYPE_MOVIE = 0; // 0x0
-    field public static final int TYPE_PLAYLIST = 10; // 0xa
-    field public static final int TYPE_STATION = 11; // 0xb
-    field public static final int TYPE_TRACK = 7; // 0x7
-    field public static final int TYPE_TV_EPISODE = 3; // 0x3
-    field public static final int TYPE_TV_SEASON = 2; // 0x2
-    field public static final int TYPE_TV_SERIES = 1; // 0x1
     field public static final int WATCH_NEXT_TYPE_CONTINUE = 0; // 0x0
     field public static final int WATCH_NEXT_TYPE_NEW = 2; // 0x2
     field public static final int WATCH_NEXT_TYPE_NEXT = 1; // 0x1
@@ -821,6 +763,7 @@
     method public boolean isSearchable();
     method public boolean isTransient();
     method public android.content.ContentValues! toContentValues();
+    field public static final String![] PROJECTION;
     field public static final int WATCH_NEXT_TYPE_UNKNOWN = -1; // 0xffffffff
   }
 
diff --git a/tvprovider/tvprovider/api/restricted_current.txt b/tvprovider/tvprovider/api/restricted_current.txt
index aa21de7..217e357 100644
--- a/tvprovider/tvprovider/api/restricted_current.txt
+++ b/tvprovider/tvprovider/api/restricted_current.txt
@@ -224,7 +224,7 @@
     method public boolean isTransient();
     method public android.content.ContentValues! toContentValues();
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.ContentValues! toContentValues(boolean);
-    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String![]! PROJECTION;
+    field public static final String![] PROJECTION;
   }
 
   public static final class PreviewProgram.Builder {
@@ -517,7 +517,7 @@
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @StringDef({androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_SD, androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_ED, androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_HD, androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_FHD, androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_UHD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface TvContractCompat.Channels.VideoResolution {
   }
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface TvContractCompat.PreviewProgramColumns {
+  public static interface TvContractCompat.PreviewProgramColumns {
     field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
     field public static final int ASPECT_RATIO_1_1 = 3; // 0x3
     field public static final int ASPECT_RATIO_2_3 = 4; // 0x4
@@ -829,7 +829,7 @@
     method public boolean isTransient();
     method public android.content.ContentValues! toContentValues();
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.ContentValues! toContentValues(boolean);
-    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String![]! PROJECTION;
+    field public static final String![] PROJECTION;
     field public static final int WATCH_NEXT_TYPE_UNKNOWN = -1; // 0xffffffff
   }
 
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java
index afe4160..9a6037a 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java
@@ -21,6 +21,7 @@
 import android.database.Cursor;
 import android.os.Build;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms;
 
@@ -76,8 +77,12 @@
  */
 public final class PreviewProgram extends BasePreviewProgram {
     /**
+     * The projection for a {@link PreviewProgram} query.
+     * <p> This provides a array of strings containing the columns to be used in the
+     * query and in creating a Cursor object, which is used to iterate through the rows in the
+     * table.
      */
-    @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @NonNull
     public static final String[] PROJECTION = getProjection();
 
     private static final long INVALID_LONG_VALUE = -1;
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
index 7d72b57..2725306 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
@@ -914,7 +914,6 @@
     /**
      * Common columns for the tables of preview programs.
      */
-    @RestrictTo(LIBRARY_GROUP_PREFIX)
     public interface PreviewProgramColumns {
         /**
          * The program type for movie.
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java
index edcb4d1..475aa87 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java
@@ -22,6 +22,7 @@
 import android.os.Build;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms;
 
@@ -79,8 +80,12 @@
  */
 public final class WatchNextProgram extends BasePreviewProgram {
     /**
+     * The projection for a {@link WatchNextProgram} query.
+     * <p> This provides a array of strings containing the columns to be used in the
+     * query and in creating a Cursor object, which is used to iterate through the rows in the
+     * table.
      */
-    @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @NonNull
     public static final String[] PROJECTION = getProjection();
 
     private static final long INVALID_LONG_VALUE = -1;
diff --git a/wear/compose/compose-foundation/api/current.txt b/wear/compose/compose-foundation/api/current.txt
index 2730513d..d723269 100644
--- a/wear/compose/compose-foundation/api/current.txt
+++ b/wear/compose/compose-foundation/api/current.txt
@@ -139,7 +139,7 @@
 
   public final class CurvedParentDataKt {
     method public static androidx.wear.compose.foundation.CurvedModifier parentDataModifier(androidx.wear.compose.foundation.CurvedModifier, kotlin.jvm.functions.Function1<java.lang.Object,?> modifyParentData);
-    method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, float weight);
+    method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, @FloatRange(from=0.0, fromInclusive=false) float weight);
   }
 
   public final class CurvedRowKt {
@@ -153,8 +153,8 @@
     method public static androidx.wear.compose.foundation.CurvedModifier angularSize(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees);
     method public static androidx.wear.compose.foundation.CurvedModifier angularSizeDp(androidx.wear.compose.foundation.CurvedModifier, float angularWidth);
     method public static androidx.wear.compose.foundation.CurvedModifier radialSize(androidx.wear.compose.foundation.CurvedModifier, float thickness);
-    method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees, float thickness);
-    method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional float minSweepDegrees, optional float maxSweepDegrees, optional float minThickness, optional float maxThickness);
+    method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, @FloatRange(from=0.0, to=360.0) float sweepDegrees, float thickness);
+    method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional @FloatRange(from=0.0, to=360.0) float minSweepDegrees, optional @FloatRange(from=0.0, to=360.0) float maxSweepDegrees, optional float minThickness, optional float maxThickness);
   }
 
   public final class CurvedTextStyle {
@@ -357,9 +357,9 @@
   }
 
   @androidx.compose.runtime.Stable @androidx.wear.compose.foundation.lazy.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
-    method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
-    method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
-    method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
+    method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
   }
 
   public sealed interface ScalingLazyListLayoutInfo {
@@ -426,20 +426,20 @@
   }
 
   @androidx.compose.runtime.Stable public interface ScalingParams {
-    method public float getEdgeAlpha();
-    method public float getEdgeScale();
-    method public float getMaxElementHeight();
-    method public float getMaxTransitionArea();
-    method public float getMinElementHeight();
-    method public float getMinTransitionArea();
+    method @FloatRange(from=0.0, to=1.0) public float getEdgeAlpha();
+    method @FloatRange(from=0.0, to=1.0) public float getEdgeScale();
+    method @FloatRange(from=0.0, to=1.0) public float getMaxElementHeight();
+    method @FloatRange(from=0.0, to=1.0) public float getMaxTransitionArea();
+    method @FloatRange(from=0.0, to=1.0) public float getMinElementHeight();
+    method @FloatRange(from=0.0, to=1.0) public float getMinTransitionArea();
     method public androidx.compose.animation.core.Easing getScaleInterpolator();
     method public int resolveViewportVerticalOffset(long viewportConstraints);
-    property public abstract float edgeAlpha;
-    property public abstract float edgeScale;
-    property public abstract float maxElementHeight;
-    property public abstract float maxTransitionArea;
-    property public abstract float minElementHeight;
-    property public abstract float minTransitionArea;
+    property @FloatRange(from=0.0, to=1.0) public abstract float edgeAlpha;
+    property @FloatRange(from=0.0, to=1.0) public abstract float edgeScale;
+    property @FloatRange(from=0.0, to=1.0) public abstract float maxElementHeight;
+    property @FloatRange(from=0.0, to=1.0) public abstract float maxTransitionArea;
+    property @FloatRange(from=0.0, to=1.0) public abstract float minElementHeight;
+    property @FloatRange(from=0.0, to=1.0) public abstract float minTransitionArea;
     property public abstract androidx.compose.animation.core.Easing scaleInterpolator;
   }
 
diff --git a/wear/compose/compose-foundation/api/restricted_current.txt b/wear/compose/compose-foundation/api/restricted_current.txt
index 2730513d..d723269 100644
--- a/wear/compose/compose-foundation/api/restricted_current.txt
+++ b/wear/compose/compose-foundation/api/restricted_current.txt
@@ -139,7 +139,7 @@
 
   public final class CurvedParentDataKt {
     method public static androidx.wear.compose.foundation.CurvedModifier parentDataModifier(androidx.wear.compose.foundation.CurvedModifier, kotlin.jvm.functions.Function1<java.lang.Object,?> modifyParentData);
-    method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, float weight);
+    method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, @FloatRange(from=0.0, fromInclusive=false) float weight);
   }
 
   public final class CurvedRowKt {
@@ -153,8 +153,8 @@
     method public static androidx.wear.compose.foundation.CurvedModifier angularSize(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees);
     method public static androidx.wear.compose.foundation.CurvedModifier angularSizeDp(androidx.wear.compose.foundation.CurvedModifier, float angularWidth);
     method public static androidx.wear.compose.foundation.CurvedModifier radialSize(androidx.wear.compose.foundation.CurvedModifier, float thickness);
-    method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees, float thickness);
-    method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional float minSweepDegrees, optional float maxSweepDegrees, optional float minThickness, optional float maxThickness);
+    method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, @FloatRange(from=0.0, to=360.0) float sweepDegrees, float thickness);
+    method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional @FloatRange(from=0.0, to=360.0) float minSweepDegrees, optional @FloatRange(from=0.0, to=360.0) float maxSweepDegrees, optional float minThickness, optional float maxThickness);
   }
 
   public final class CurvedTextStyle {
@@ -357,9 +357,9 @@
   }
 
   @androidx.compose.runtime.Stable @androidx.wear.compose.foundation.lazy.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
-    method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
-    method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
-    method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
+    method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
   }
 
   public sealed interface ScalingLazyListLayoutInfo {
@@ -426,20 +426,20 @@
   }
 
   @androidx.compose.runtime.Stable public interface ScalingParams {
-    method public float getEdgeAlpha();
-    method public float getEdgeScale();
-    method public float getMaxElementHeight();
-    method public float getMaxTransitionArea();
-    method public float getMinElementHeight();
-    method public float getMinTransitionArea();
+    method @FloatRange(from=0.0, to=1.0) public float getEdgeAlpha();
+    method @FloatRange(from=0.0, to=1.0) public float getEdgeScale();
+    method @FloatRange(from=0.0, to=1.0) public float getMaxElementHeight();
+    method @FloatRange(from=0.0, to=1.0) public float getMaxTransitionArea();
+    method @FloatRange(from=0.0, to=1.0) public float getMinElementHeight();
+    method @FloatRange(from=0.0, to=1.0) public float getMinTransitionArea();
     method public androidx.compose.animation.core.Easing getScaleInterpolator();
     method public int resolveViewportVerticalOffset(long viewportConstraints);
-    property public abstract float edgeAlpha;
-    property public abstract float edgeScale;
-    property public abstract float maxElementHeight;
-    property public abstract float maxTransitionArea;
-    property public abstract float minElementHeight;
-    property public abstract float minTransitionArea;
+    property @FloatRange(from=0.0, to=1.0) public abstract float edgeAlpha;
+    property @FloatRange(from=0.0, to=1.0) public abstract float edgeScale;
+    property @FloatRange(from=0.0, to=1.0) public abstract float maxElementHeight;
+    property @FloatRange(from=0.0, to=1.0) public abstract float maxTransitionArea;
+    property @FloatRange(from=0.0, to=1.0) public abstract float minElementHeight;
+    property @FloatRange(from=0.0, to=1.0) public abstract float minTransitionArea;
     property public abstract androidx.compose.animation.core.Easing scaleInterpolator;
   }
 
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedParentData.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedParentData.kt
index aedafea..14d4b39 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedParentData.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedParentData.kt
@@ -16,6 +16,8 @@
 
 package androidx.wear.compose.foundation
 
+import androidx.annotation.FloatRange
+
 /**
  * A [CurvedModifier] that provides data to the parent layout.
  * The parent data is commonly used to inform the parent how the child Layout should be measured
@@ -41,7 +43,7 @@
  * all weighted siblings. Must be positive.
  */
 public fun CurvedModifier.weight(
-    /* @FloatRange(from = 0f, fromInclusive = false) */
+    @FloatRange(from = 0.0, fromInclusive = false)
     weight: Float
 ) = parentDataModifier { parentData ->
     require(weight > 0f) { "Weights must be positive." }
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedSize.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedSize.kt
index 8e0408c..6c90d7a 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedSize.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedSize.kt
@@ -16,6 +16,7 @@
 
 package androidx.wear.compose.foundation
 
+import androidx.annotation.FloatRange
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.layout.Measurable
 import androidx.compose.ui.unit.Dp
@@ -30,9 +31,9 @@
  * @param maxThickness the maximum thickness (radial size) for the content.
  */
 public fun CurvedModifier.sizeIn(
-    /* @FloatRange(from = 0f, to = 360f) */
+    @FloatRange(from = 0.0, to = 360.0)
     minSweepDegrees: Float = 0f,
-    /* @FloatRange(from = 0f, to = 360f) */
+    @FloatRange(from = 0.0, to = 360.0)
     maxSweepDegrees: Float = 360f,
     minThickness: Dp = 0.dp,
     maxThickness: Dp = Dp.Infinity,
@@ -54,10 +55,12 @@
  * @param sweepDegrees Indicates the sweep (angular size) of the content.
  * @param thickness Indicates the thickness (radial size) of the content.
  */
-public fun CurvedModifier.size(sweepDegrees: Float, thickness: Dp) = sizeIn(
-    /* @FloatRange(from = 0f, to = 360f) */
+public fun CurvedModifier.size(
+    @FloatRange(from = 0.0, to = 360.0)
+    sweepDegrees: Float,
+    thickness: Dp
+) = sizeIn(
     minSweepDegrees = sweepDegrees,
-    /* @FloatRange(from = 0f, to = 360f) */
     maxSweepDegrees = sweepDegrees,
     minThickness = thickness,
     maxThickness = thickness
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeToReveal.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeToReveal.kt
index 2f4d683..7662003 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeToReveal.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeToReveal.kt
@@ -260,10 +260,10 @@
  *
  * @param action The mandatory action that needs to be added to the component.
  * @param modifier Optional [Modifier] for this component.
- * @param state The [RevealState] of this component. It can be used to customise the anchors
- * and threshold config of the swipeable modifier which is applied.
  * @param onFullSwipe An optional lambda which will be triggered when a full swipe from either of
  * the anchors is performed.
+ * @param state The [RevealState] of this component. It can be used to customise the anchors
+ * and threshold config of the swipeable modifier which is applied.
  * @param additionalAction The optional action that can be added to the component.
  * @param undoAction The optional undo action that will be applied to the component once the
  * mandatory action has been performed.
@@ -388,12 +388,13 @@
      * anchor for [RevealValue.Revealing].
      * If there is no such anchor defined for [RevealValue.Revealing], it returns 0.0f.
      */
+    /* @FloatRange(from = 0.0) */
     public val revealOffset: Float
 }
 
 @OptIn(ExperimentalWearFoundationApi::class)
 private class RevealScopeImpl constructor(
-    private val revealState: RevealState
+    val revealState: RevealState,
 ) : RevealScope {
 
     /**
@@ -430,7 +431,9 @@
     content: @Composable RevealScope.() -> Unit
 ) {
     Box(
-        modifier = modifier.fillMaxHeight().weight(weight),
+        modifier = modifier
+            .fillMaxHeight()
+            .weight(weight),
         contentAlignment = Alignment.Center
     ) {
         with(revealScope) {
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt
index 15a2dde..ff97315 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt
@@ -16,6 +16,7 @@
 
 package androidx.wear.compose.foundation
 
+import androidx.annotation.FloatRange
 import androidx.annotation.RestrictTo
 import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
 import androidx.compose.animation.core.AnimationSpec
@@ -296,7 +297,7 @@
      * The fraction of the progress going from [currentValue] to [targetValue], within [0f..1f]
      * bounds.
      */
-    /*@FloatRange(from = 0f, to = 1f)*/
+    @get:FloatRange(from = 0.0, to = 1.0)
     val progress: Float by derivedStateOf {
         val a = anchors[currentValue] ?: 0f
         val b = anchors[targetValue] ?: 0f
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
index 9f65cce..7584d68 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
@@ -16,6 +16,7 @@
 
 package androidx.wear.compose.foundation.lazy
 
+import androidx.annotation.FloatRange
 import androidx.annotation.RestrictTo
 import androidx.compose.animation.core.Easing
 import androidx.compose.foundation.gestures.Orientation
@@ -100,9 +101,7 @@
      * scaled, e.g. at the edge of the viewport. A value between [0f,1f], so a value of 0.2f
      * means to scale an item to 20% of its normal size.
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val edgeScale: Float
 
     /**
@@ -110,9 +109,7 @@
      * when closest to the edge of the screen. A value between [0f,1f], so a value of
      * 0.2f means to set the alpha of an item to 20% of its normal value.
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val edgeAlpha: Float
 
     /**
@@ -122,9 +119,7 @@
      * will be treated as if [maxElementHeight]. Must be greater than or equal to
      * [minElementHeight].
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val minElementHeight: Float
 
     /**
@@ -134,9 +129,7 @@
      * will be treated as if [maxElementHeight]. Must be greater than or equal to
      * [minElementHeight].
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val maxElementHeight: Float
 
     /**
@@ -153,9 +146,7 @@
      * list items exist. Depending on the size of the list item the specific point in the area is
      * calculated.
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val minTransitionArea: Float
 
     /**
@@ -172,9 +163,7 @@
      * list items exist. Depending on the size of the list item the specific point in the area is
      * calculated.
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val maxTransitionArea: Float
 
     /**
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyListItemScope.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyListItemScope.kt
index 042e928..aac594e 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyListItemScope.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyListItemScope.kt
@@ -15,6 +15,7 @@
  */
 package androidx.wear.compose.foundation.lazy
 
+import androidx.annotation.FloatRange
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
@@ -42,7 +43,7 @@
      * measured with [Constraints.Infinity] as the constraints for the main axis.
      */
     fun Modifier.fillParentMaxSize(
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         fraction: Float = 1f
     ): Modifier
 
@@ -57,7 +58,7 @@
      * items are measured with [Constraints.Infinity] as the constraints for the main axis.
      */
     fun Modifier.fillParentMaxWidth(
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         fraction: Float = 1f
     ): Modifier
 
@@ -72,7 +73,7 @@
      * items are measured with [Constraints.Infinity] as the constraints for the main axis.
      */
     fun Modifier.fillParentMaxHeight(
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         fraction: Float = 1f
     ): Modifier
 }
diff --git a/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/ToggleButtonTest.kt b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/ToggleButtonTest.kt
index 1b93f3a..6bd0e3c 100644
--- a/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/ToggleButtonTest.kt
+++ b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/ToggleButtonTest.kt
@@ -18,6 +18,7 @@
 
 import android.os.Build
 import androidx.annotation.RequiresApi
+import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.background
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Box
@@ -25,9 +26,14 @@
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.RowScope
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.foundation.shape.CutCornerShape
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.State
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -35,16 +41,21 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.compositeOver
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.Role
 import androidx.compose.ui.semantics.SemanticsProperties
 import androidx.compose.ui.test.SemanticsMatcher
 import androidx.compose.ui.test.assert
 import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertHeightIsEqualTo
 import androidx.compose.ui.test.assertIsEnabled
 import androidx.compose.ui.test.assertIsNotEnabled
 import androidx.compose.ui.test.assertIsOff
 import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.assertTouchHeightIsEqualTo
+import androidx.compose.ui.test.assertTouchWidthIsEqualTo
+import androidx.compose.ui.test.assertWidthIsEqualTo
 import androidx.compose.ui.test.captureToImage
 import androidx.compose.ui.test.isToggleable
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -53,7 +64,9 @@
 import androidx.compose.ui.test.onNodeWithText
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
+import org.junit.Assert
 import org.junit.Rule
 import org.junit.Test
 
@@ -61,8 +74,353 @@
     @get:Rule
     val rule = createComposeRule()
 
+    /* Round Toggle buttons */
     @Test
-    fun supports_testtag() {
+    fun round_toggle_button_supports_testTag() {
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG),
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertExists()
+    }
+
+    @Test
+    fun round_toggle_button_is_toggleable() {
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNode(isToggleable()).assertExists()
+    }
+
+    @Test
+    fun round_toggle_button_has_click_action_when_enabled() {
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+    }
+
+    @Test
+    fun round_toggle_button_has_click_action_when_disabled() {
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+    }
+
+    @Test
+    fun round_toggle_button_is_correctly_enabled() {
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
+    }
+
+    @Test
+    fun round_toggle_button_is_correctly_disabled() {
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertIsNotEnabled()
+    }
+
+    @Test
+    fun round_toggle_button_is_on_when_checked() {
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                enabled = true,
+                checked = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertIsOn()
+    }
+
+    @Test
+    fun round_toggle_button_is_off_when_unchecked() {
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                enabled = true,
+                checked = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertIsOff()
+    }
+
+    @Test
+    fun round_toggle_button_toggles_when_enabled() {
+        var clicked = false
+
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                enabled = true,
+                onCheckedChange = { clicked = true },
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).performClick()
+
+        rule.runOnIdle {
+            Assert.assertEquals(true, clicked)
+        }
+    }
+
+    @Test
+    fun round_toggle_button_responds_to_toggle_on() {
+        rule.setContent {
+            val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+            RoundToggleButtonWithDefaults(
+                content = { TestImage() },
+                checked = checked,
+                onCheckedChange = onCheckedChange,
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule
+            .onNodeWithTag(TEST_TAG)
+            .assertIsOff()
+            .performClick()
+            .assertIsOn()
+    }
+
+    @Test
+    fun round_toggle_button_responds_to_toggle_off() {
+        rule.setContent {
+            val (checked, onCheckedChange) = remember { mutableStateOf(true) }
+            RoundToggleButtonWithDefaults(
+                content = { TestImage() },
+                checked = checked,
+                onCheckedChange = onCheckedChange,
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule
+            .onNodeWithTag(TEST_TAG)
+            .assertIsOn()
+            .performClick()
+            .assertIsOff()
+    }
+
+    @Test
+    fun round_toggle_button_does_not_respond_to_click_when_disabled() {
+        var clicked = false
+
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                onCheckedChange = { clicked = true },
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).performClick()
+
+        rule.runOnIdle {
+            Assert.assertEquals(false, clicked)
+        }
+    }
+
+    @Test
+    fun round_toggle_button_has_role_checkbox() {
+        rule.setContent {
+            RoundToggleButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .assert(
+                SemanticsMatcher.expectValue(
+                    SemanticsProperties.Role,
+                    Role.Checkbox
+                )
+            )
+    }
+
+    @Test
+    fun round_toggle_button_supports_circle_shape_under_ltr() =
+        rule.isShape(CircleShape, LayoutDirection.Ltr) {
+            RoundToggleButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG),
+            ) { }
+        }
+
+    @Test
+    fun round_toggle_button_supports_circle_shape_under_rtl() =
+        rule.isShape(CircleShape, LayoutDirection.Rtl) {
+            RoundToggleButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG),
+            ) { }
+        }
+
+    @Test
+    fun extra_small_round_toggle_button_meets_accessibility_tapSize() {
+        verifyTapSize(48.dp) {
+            RoundToggleButtonWithDefaults(
+                modifier = Modifier
+                    .testTag(TEST_TAG)
+                    .size(32.dp)
+            )
+        }
+    }
+
+    @Test
+    fun extra_small_round_toggle_button_has_correct_visible_size() {
+        verifyVisibleSize(32.dp) {
+            RoundToggleButtonWithDefaults(
+                modifier = Modifier
+                    .testTag(TEST_TAG)
+                    .requiredSize(32.dp)
+            )
+        }
+    }
+
+    @Test
+    fun default_round_toggle_button_has_correct_tapSize() {
+        // Tap size for Button should be 52.dp.
+        verifyTapSize(52.dp) {
+            RoundToggleButtonWithDefaults(
+                modifier = Modifier
+                    .testTag(TEST_TAG)
+                    .size(52.dp)
+            )
+        }
+    }
+
+    @Test
+    fun default_round_toggle_button_has_correct_visible_size() {
+        // Tap size for Button should be 52.dp.
+        verifyVisibleSize(52.dp) {
+            RoundToggleButtonWithDefaults(
+                modifier = Modifier
+                    .testTag(TEST_TAG)
+                    .size(52.dp)
+            )
+        }
+    }
+
+    @Test
+    fun round_toggle_button_allows_custom_shape_override() {
+        val shape = CutCornerShape(4.dp)
+
+        rule.isShape(shape, LayoutDirection.Ltr) {
+            RoundToggleButtonWithDefaults(
+                shape = shape,
+                modifier = Modifier.testTag(TEST_TAG)
+            ) { }
+        }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun round_toggle_button_gives_correct_colors_when_enabled() =
+        verifyToggleButtonColors(
+            enabled = true,
+            checked = false,
+            { enabled, _ -> remember { mutableStateOf(if (enabled) Color.Green else Color.Red) } },
+            { enabled, _ ->
+                remember { mutableStateOf(if (enabled) Color.Blue else Color.Yellow) }
+            },
+            Color.Green,
+            Color.Blue
+        )
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun round_toggle_button_gives_correct_colors_when_disabled() =
+        verifyToggleButtonColors(
+            enabled = false,
+            checked = false,
+            { enabled, _ -> remember { mutableStateOf(if (enabled) Color.Green else Color.Red) } },
+            { enabled, _ ->
+                remember { mutableStateOf(if (enabled) Color.Blue else Color.Yellow) }
+            },
+            Color.Red,
+            Color.Yellow,
+        )
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun round_toggle_button_gives_correct_colors_when_checked() =
+        verifyToggleButtonColors(
+            enabled = true,
+            checked = true,
+            { _, checked -> remember { mutableStateOf(if (checked) Color.Green else Color.Red) } },
+            { _, checked ->
+                remember { mutableStateOf(if (checked) Color.Blue else Color.Yellow) }
+            },
+            Color.Green,
+            Color.Blue,
+        )
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun round_toggle_button_gives_correct_colors_when_unchecked() =
+        verifyToggleButtonColors(
+            enabled = true,
+            checked = false,
+            { _, checked -> remember { mutableStateOf(if (checked) Color.Green else Color.Red) } },
+            { _, checked ->
+                remember { mutableStateOf(if (checked) Color.Blue else Color.Yellow) }
+            },
+            Color.Red,
+            Color.Yellow,
+        )
+
+    @Test
+    fun round_toggle_button_obeys_content_provider_values() {
+        var data = -1
+
+        rule.setContent {
+            Box(modifier = Modifier.fillMaxSize()) {
+                RoundToggleButtonWithDefaults(
+                    content = {
+                        CompositionLocalProvider(
+                            LocalContentTestData provides EXPECTED_LOCAL_TEST_DATA
+                        ) {
+                            data = LocalContentTestData.current
+                        }
+                    }
+                )
+            }
+        }
+
+        Assert.assertEquals(data, EXPECTED_LOCAL_TEST_DATA)
+    }
+
+    /* Toggle button */
+    @Test
+    fun toggle_button_supports_testTag() {
         rule.setContent {
             ToggleButtonWithDefaults(
                 modifier = Modifier.testTag(TEST_TAG)
@@ -73,18 +431,7 @@
     }
 
     @Test
-    fun split_button_supports_testtag() {
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule.onNodeWithTag(TEST_TAG).assertExists()
-    }
-
-    @Test
-    fun has_clickaction_when_enabled() {
+    fun toggle_button_has_click_action_when_enabled() {
         rule.setContent {
             ToggleButtonWithDefaults(
                 enabled = true,
@@ -96,19 +443,7 @@
     }
 
     @Test
-    fun split_button_has_clickaction_when_enabled() {
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                enabled = true,
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
-    }
-
-    @Test
-    fun has_clickaction_when_disabled() {
+    fun toggle_button_has_click_action_when_disabled() {
         rule.setContent {
             ToggleButtonWithDefaults(
                 enabled = false,
@@ -120,19 +455,7 @@
     }
 
     @Test
-    fun split_button_has_clickaction_when_disabled() {
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                enabled = false,
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
-    }
-
-    @Test
-    fun is_toggleable() {
+    fun toggle_button_is_toggleable() {
         rule.setContent {
             ToggleButtonWithDefaults(
                 modifier = Modifier.testTag(TEST_TAG)
@@ -143,52 +466,7 @@
     }
 
     @Test
-    fun split_button_is_toggleable() {
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule.onNode(isToggleable()).assertExists()
-    }
-
-    @Test
-    fun split_button_is_clickable() {
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-        rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
-    }
-
-    @Test
-    fun is_correctly_enabled() {
-        rule.setContent {
-            ToggleButtonWithDefaults(
-                enabled = true,
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
-    }
-
-    @Test
-    fun split_button_is_correctly_enabled() {
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                enabled = true,
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
-    }
-
-    @Test
-    fun is_correctly_disabled() {
+    fun toggle_button_is_correctly_disabled() {
         rule.setContent {
             ToggleButtonWithDefaults(
                 enabled = false,
@@ -200,19 +478,19 @@
     }
 
     @Test
-    fun split_button_is_correctly_disabled() {
+    fun toggle_button_is_correctly_enabled() {
         rule.setContent {
-            SplitToggleButtonWithDefaults(
-                enabled = false,
+            ToggleButtonWithDefaults(
+                enabled = true,
                 modifier = Modifier.testTag(TEST_TAG)
             )
         }
 
-        rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertIsNotEnabled()
+        rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
     }
 
     @Test
-    fun is_on_when_checked() {
+    fun toggle_button_is_on_when_checked() {
         rule.setContent {
             ToggleButtonWithDefaults(
                 checked = true,
@@ -224,19 +502,7 @@
     }
 
     @Test
-    fun split_button_is_on_when_checked() {
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                checked = true,
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule.onNodeWithTag(TEST_TAG).onChildAt(1).assertIsOn()
-    }
-
-    @Test
-    fun is_off_when_unchecked() {
+    fun toggle_button_is_off_when_unchecked() {
         rule.setContent {
             ToggleButtonWithDefaults(
                 checked = false,
@@ -248,19 +514,7 @@
     }
 
     @Test
-    fun split_button_is_off_when_unchecked() {
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                checked = false,
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule.onNodeWithTag(TEST_TAG).onChildAt(1).assertIsOff()
-    }
-
-    @Test
-    fun responds_to_toggle_on() {
+    fun toggle_button_responds_to_toggle_on() {
         rule.setContent {
             val (checked, onCheckedChange) = remember { mutableStateOf(false) }
             ToggleButtonWithDefaults(
@@ -279,27 +533,7 @@
     }
 
     @Test
-    fun split_button_responds_to_toggle_on() {
-        rule.setContent {
-            val (checked, onCheckedChange) = remember { mutableStateOf(false) }
-            SplitToggleButtonWithDefaults(
-                checked = checked,
-                onCheckedChange = onCheckedChange,
-                enabled = true,
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule
-            .onNodeWithTag(TEST_TAG)
-            .onChildAt(1)
-            .assertIsOff()
-            .performClick()
-            .assertIsOn()
-    }
-
-    @Test
-    fun responds_to_toggle_off() {
+    fun toggle_button_responds_to_toggle_off() {
         rule.setContent {
             val (checked, onCheckedChange) = remember { mutableStateOf(true) }
             ToggleButtonWithDefaults(
@@ -318,27 +552,7 @@
     }
 
     @Test
-    fun split_button_responds_to_toggle_off() {
-        rule.setContent {
-            val (checked, onCheckedChange) = remember { mutableStateOf(true) }
-            SplitToggleButtonWithDefaults(
-                checked = checked,
-                onCheckedChange = onCheckedChange,
-                enabled = true,
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule
-            .onNodeWithTag(TEST_TAG)
-            .onChildAt(1)
-            .assertIsOn()
-            .performClick()
-            .assertIsOff()
-    }
-
-    @Test
-    fun does_not_toggle_when_disabled() {
+    fun toggle_button_does_not_toggle_when_disabled() {
         rule.setContent {
             val (checked, onCheckedChange) = remember { mutableStateOf(false) }
             ToggleButtonWithDefaults(
@@ -357,27 +571,7 @@
     }
 
     @Test
-    fun split_button_does_not_toggle_when_disabled() {
-        rule.setContent {
-            val (checked, onCheckedChange) = remember { mutableStateOf(false) }
-            SplitToggleButtonWithDefaults(
-                checked = checked,
-                onCheckedChange = onCheckedChange,
-                enabled = false,
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule
-            .onNodeWithTag(TEST_TAG)
-            .onChildAt(1)
-            .assertIsOff()
-            .performClick()
-            .assertIsOff()
-    }
-
-    @Test
-    fun has_role_checkbox() {
+    fun toggle_button_has_role_checkbox() {
         rule.setContent {
             ToggleButtonWithDefaults(
                 modifier = Modifier.testTag(TEST_TAG)
@@ -394,32 +588,7 @@
     }
 
     @Test
-    fun split_button_has_roles_button_and_checkbox() {
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                modifier = Modifier.testTag(TEST_TAG)
-            )
-        }
-
-        rule.onNodeWithTag(TEST_TAG).onChildAt(0)
-            .assert(
-                SemanticsMatcher.expectValue(
-                    SemanticsProperties.Role,
-                    Role.Button
-                )
-            )
-
-        rule.onNodeWithTag(TEST_TAG).onChildAt(1)
-            .assert(
-                SemanticsMatcher.expectValue(
-                    SemanticsProperties.Role,
-                    Role.Checkbox
-                )
-            )
-    }
-
-    @Test
-    fun displays_label_content() {
+    fun toggle_button_displays_label_content() {
         val textContent = "abc"
 
         rule.setContent {
@@ -435,23 +604,6 @@
         rule.onNodeWithText(textContent).assertExists()
     }
 
-    @Test
-    fun split_button_displays_label_content() {
-        val textContent = "abc"
-
-        rule.setContent {
-            SplitToggleButtonWithDefaults(
-                checked = true,
-                onCheckedChange = {},
-                label = {
-                    TestText(text = textContent)
-                }
-            )
-        }
-
-        rule.onNodeWithText(textContent).assertExists()
-    }
-
     @RequiresApi(Build.VERSION_CODES.O)
     @Test
     fun toggle_button_allows_checked_background_color_override() =
@@ -488,6 +640,214 @@
             expectedColor = DISABLED_UNCHECKED_COLOR
         )
 
+    /* Split toggle buttons */
+
+    @Test
+    fun split_button_supports_testTag() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertExists()
+    }
+
+    @Test
+    fun split_button_has_click_action_when_enabled() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
+    }
+
+    @Test
+    fun split_button_has_click_action_when_disabled() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
+    }
+
+    @Test
+    fun split_button_is_toggleable() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNode(isToggleable()).assertExists()
+    }
+
+    @Test
+    fun split_button_is_clickable() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+        rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
+    }
+
+    @Test
+    fun split_button_is_correctly_enabled() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
+    }
+
+    @Test
+    fun split_button_is_correctly_disabled() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertIsNotEnabled()
+    }
+
+    @Test
+    fun split_button_is_off_when_unchecked() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                checked = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).onChildAt(1).assertIsOff()
+    }
+
+    @Test
+    fun split_button_is_on_when_checked() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                checked = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).onChildAt(1).assertIsOn()
+    }
+
+    @Test
+    fun split_button_responds_to_toggle_on() {
+        rule.setContent {
+            val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+            SplitToggleButtonWithDefaults(
+                checked = checked,
+                onCheckedChange = onCheckedChange,
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule
+            .onNodeWithTag(TEST_TAG)
+            .onChildAt(1)
+            .assertIsOff()
+            .performClick()
+            .assertIsOn()
+    }
+
+    @Test
+    fun split_button_responds_to_toggle_off() {
+        rule.setContent {
+            val (checked, onCheckedChange) = remember { mutableStateOf(true) }
+            SplitToggleButtonWithDefaults(
+                checked = checked,
+                onCheckedChange = onCheckedChange,
+                enabled = true,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule
+            .onNodeWithTag(TEST_TAG)
+            .onChildAt(1)
+            .assertIsOn()
+            .performClick()
+            .assertIsOff()
+    }
+
+    @Test
+    fun split_button_does_not_toggle_when_disabled() {
+        rule.setContent {
+            val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+            SplitToggleButtonWithDefaults(
+                checked = checked,
+                onCheckedChange = onCheckedChange,
+                enabled = false,
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule
+            .onNodeWithTag(TEST_TAG)
+            .onChildAt(1)
+            .assertIsOff()
+            .performClick()
+            .assertIsOff()
+    }
+
+    @Test
+    fun split_button_has_roles_button_and_checkbox() {
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                modifier = Modifier.testTag(TEST_TAG)
+            )
+        }
+
+        rule.onNodeWithTag(TEST_TAG).onChildAt(0)
+            .assert(
+                SemanticsMatcher.expectValue(
+                    SemanticsProperties.Role,
+                    Role.Button
+                )
+            )
+
+        rule.onNodeWithTag(TEST_TAG).onChildAt(1)
+            .assert(
+                SemanticsMatcher.expectValue(
+                    SemanticsProperties.Role,
+                    Role.Checkbox
+                )
+            )
+    }
+
+    @Test
+    fun split_button_displays_label_content() {
+        val textContent = "abc"
+
+        rule.setContent {
+            SplitToggleButtonWithDefaults(
+                checked = true,
+                onCheckedChange = {},
+                label = {
+                    TestText(text = textContent)
+                }
+            )
+        }
+
+        rule.onNodeWithText(textContent).assertExists()
+    }
+
     @RequiresApi(Build.VERSION_CODES.O)
     @Test
     fun split_toggle_button_allows_checked_background_color_override() =
@@ -586,6 +946,109 @@
             .captureToImage()
             .assertContainsColor(expectedColor)
     }
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    private fun verifyToggleButtonColors(
+        enabled: Boolean,
+        checked: Boolean,
+        backgroundColor: @Composable (Boolean, Boolean) -> State<Color>,
+        borderColor: @Composable (Boolean, Boolean) -> State<Color>,
+        expectedBackgroundColor: Color,
+        expectedBorderColor: Color,
+        backgroundThreshold: Float = 50.0f,
+        borderThreshold: Float = 1.0f,
+    ) {
+        val testBackground = Color.White
+        val expectedColor = { color: Color ->
+            if (color != Color.Transparent)
+                color.compositeOver(testBackground)
+            else
+                testBackground
+        }
+
+        rule.setContent {
+            Box(
+                modifier = Modifier
+                    .fillMaxSize()
+                    .background(testBackground)
+            ) {
+                val actualBorderColor = borderColor(enabled, checked).value
+                val border = remember { mutableStateOf(BorderStroke(2.dp, actualBorderColor)) }
+                RoundToggleButtonWithDefaults(
+                    backgroundColor = backgroundColor,
+                    border = { _, _ -> return@RoundToggleButtonWithDefaults border },
+                    enabled = enabled,
+                    checked = checked,
+                    modifier = Modifier.testTag(TEST_TAG)
+                ) {
+                }
+            }
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertContainsColor(expectedColor(expectedBackgroundColor), backgroundThreshold)
+        rule.onNodeWithTag(TEST_TAG)
+            .captureToImage()
+            .assertContainsColor(expectedColor(expectedBorderColor), borderThreshold)
+    }
+
+    private fun verifyTapSize(
+        expected: Dp,
+        content: @Composable () -> Unit
+    ) {
+        rule.setContent {
+            content()
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .assertTouchHeightIsEqualTo(expected)
+            .assertTouchWidthIsEqualTo(expected)
+    }
+
+    private fun verifyVisibleSize(
+        expected: Dp,
+        content: @Composable () -> Unit
+    ) {
+        rule.setContent {
+            content()
+        }
+
+        rule.onNodeWithTag(TEST_TAG)
+            .assertHeightIsEqualTo(expected)
+            .assertWidthIsEqualTo(expected)
+    }
+}
+
+@Composable
+private fun RoundToggleButtonWithDefaults(
+    modifier: Modifier = Modifier,
+    checked: Boolean = true,
+    onCheckedChange: (Boolean) -> Unit = {},
+    enabled: Boolean = true,
+    backgroundColor: @Composable (enabled: Boolean, checked: Boolean) -> State<Color> =
+        { _, _ -> rememberUpdatedState(DEFAULT_SHAPE_COLOR) },
+    border: @Composable (enabled: Boolean, checked: Boolean) -> State<BorderStroke?>? =
+        { _, _ -> null },
+    toggleButtonSize: Dp = 52.dp,
+    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+    shape: Shape = CircleShape,
+    content: @Composable BoxScope.() -> Unit = {
+        TestText(text = "Label")
+    }
+) {
+    ToggleButton(
+        checked = checked,
+        onCheckedChange = onCheckedChange,
+        modifier = modifier,
+        enabled = enabled,
+        backgroundColor = backgroundColor,
+        border = border,
+        toggleButtonSize = toggleButtonSize,
+        interactionSource = interactionSource,
+        shape = shape,
+        content = content
+    )
 }
 
 @Composable
diff --git a/wear/compose/compose-material/api/current.txt b/wear/compose/compose-material/api/current.txt
index c1b45d8..099285e 100644
--- a/wear/compose/compose-material/api/current.txt
+++ b/wear/compose/compose-material/api/current.txt
@@ -207,9 +207,9 @@
   }
 
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class FractionalThreshold implements androidx.wear.compose.material.ThresholdConfig {
-    ctor public FractionalThreshold(float fraction);
+    ctor public FractionalThreshold(@FloatRange(from=0.0, to=1.0) float fraction);
     method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
-    method public androidx.wear.compose.material.FractionalThreshold copy(float fraction);
+    method public androidx.wear.compose.material.FractionalThreshold copy(@FloatRange(from=0.0, to=1.0) float fraction);
   }
 
   public final class HorizontalPageIndicatorKt {
@@ -326,10 +326,10 @@
   }
 
   public final class PickerKt {
-    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
-    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
-    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
-    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
     method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerState rememberPickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
   }
 
@@ -412,10 +412,10 @@
   }
 
   @androidx.compose.runtime.Stable public interface PositionIndicatorState {
-    method public float getPositionFraction();
-    method public float sizeFraction(float scrollableContainerSizePx);
-    method public int visibility(float scrollableContainerSizePx);
-    property public abstract float positionFraction;
+    method @FloatRange(from=0.0, to=1.0) public float getPositionFraction();
+    method @FloatRange(from=0.0, to=1.0) public float sizeFraction(@FloatRange(from=0.0) float scrollableContainerSizePx);
+    method public int visibility(@FloatRange(from=0.0) float scrollableContainerSizePx);
+    property @FloatRange(from=0.0, to=1.0) public abstract float positionFraction;
   }
 
   @kotlin.jvm.JvmInline public final value class PositionIndicatorVisibility {
@@ -441,7 +441,7 @@
 
   public final class ProgressIndicatorKt {
     method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
-    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional float endAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
+    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(@FloatRange(from=0.0, to=1.0) float progress, optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional float endAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
   }
 
   @androidx.compose.runtime.Stable public interface RadioButtonColors {
@@ -455,7 +455,7 @@
   }
 
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class ResistanceConfig {
-    ctor public ResistanceConfig(float basis, optional float factorAtMin, optional float factorAtMax);
+    ctor public ResistanceConfig(@FloatRange(from=0.0, fromInclusive=false) float basis, optional @FloatRange(from=0.0) float factorAtMin, optional @FloatRange(from=0.0) float factorAtMax);
     method public float computeResistance(float overflow);
     method public float getBasis();
     method public float getFactorAtMax();
@@ -514,9 +514,9 @@
   }
 
   @Deprecated @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
-    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
-    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
-    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
+    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
   }
 
   @Deprecated public sealed interface ScalingLazyListLayoutInfo {
@@ -581,20 +581,20 @@
   }
 
   @Deprecated @androidx.compose.runtime.Stable public interface ScalingParams {
-    method @Deprecated public float getEdgeAlpha();
-    method @Deprecated public float getEdgeScale();
-    method @Deprecated public float getMaxElementHeight();
-    method @Deprecated public float getMaxTransitionArea();
-    method @Deprecated public float getMinElementHeight();
-    method @Deprecated public float getMinTransitionArea();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getEdgeAlpha();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getEdgeScale();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMaxElementHeight();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMaxTransitionArea();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMinElementHeight();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMinTransitionArea();
     method @Deprecated public androidx.compose.animation.core.Easing getScaleInterpolator();
     method @Deprecated public int resolveViewportVerticalOffset(long viewportConstraints);
-    property @Deprecated public abstract float edgeAlpha;
-    property @Deprecated public abstract float edgeScale;
-    property @Deprecated public abstract float maxElementHeight;
-    property @Deprecated public abstract float maxTransitionArea;
-    property @Deprecated public abstract float minElementHeight;
-    property @Deprecated public abstract float minTransitionArea;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float edgeAlpha;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float edgeScale;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float maxElementHeight;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float maxTransitionArea;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float minElementHeight;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float minTransitionArea;
     property @Deprecated public abstract androidx.compose.animation.core.Easing scaleInterpolator;
   }
 
@@ -645,7 +645,7 @@
   }
 
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeProgress<T> {
-    ctor public SwipeProgress(T from, T to, float fraction);
+    ctor public SwipeProgress(T from, T to, @FloatRange(from=0.0, to=1.0) float fraction);
     method public float getFraction();
     method public T getFrom();
     method public T getTo();
@@ -694,6 +694,55 @@
     enum_constant public static final androidx.wear.compose.material.SwipeToDismissValue Dismissed;
   }
 
+  @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealAction {
+    ctor public SwipeToRevealAction(kotlin.jvm.functions.Function0<kotlin.Unit>? icon, kotlin.jvm.functions.Function0<kotlin.Unit>? label, androidx.compose.ui.Modifier modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public kotlin.jvm.functions.Function0<kotlin.Unit>? getIcon();
+    method public androidx.compose.foundation.interaction.MutableInteractionSource getInteractionSource();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit>? getLabel();
+    method public androidx.compose.ui.Modifier getModifier();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit> getOnClick();
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit>? icon;
+    property public final androidx.compose.foundation.interaction.MutableInteractionSource interactionSource;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit>? label;
+    property public final androidx.compose.ui.Modifier modifier;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit> onClick;
+  }
+
+  @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealActionColors {
+    ctor public SwipeToRevealActionColors(long actionBackgroundColor, long actionContentColor, long additionalActionBackgroundColor, long additionalActionContentColor, long undoActionBackgroundColor, long undoActionContentColor);
+    method public long getActionBackgroundColor();
+    method public long getActionContentColor();
+    method public long getAdditionalActionBackgroundColor();
+    method public long getAdditionalActionContentColor();
+    method public long getUndoActionBackgroundColor();
+    method public long getUndoActionContentColor();
+    property public final long actionBackgroundColor;
+    property public final long actionContentColor;
+    property public final long additionalActionBackgroundColor;
+    property public final long additionalActionContentColor;
+    property public final long undoActionBackgroundColor;
+    property public final long undoActionContentColor;
+  }
+
+  @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealDefaults {
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction action(kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealActionColors actionColors(optional long actionBackgroundColor, optional long actionContentColor, optional long additionalActionBackgroundColor, optional long additionalActionContentColor, optional long undoActionBackgroundColor, optional long undoActionContentColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction additionalAction(kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public androidx.compose.foundation.shape.RoundedCornerShape getCardActionShape();
+    method public androidx.compose.ui.graphics.vector.ImageVector getDelete();
+    method public androidx.compose.ui.graphics.vector.ImageVector getMoreOptions();
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction undoAction(kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    property public final androidx.compose.foundation.shape.RoundedCornerShape CardActionShape;
+    property public final androidx.compose.ui.graphics.vector.ImageVector Delete;
+    property public final androidx.compose.ui.graphics.vector.ImageVector MoreOptions;
+    field public static final androidx.wear.compose.material.SwipeToRevealDefaults INSTANCE;
+  }
+
+  public final class SwipeToRevealKt {
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.material.ExperimentalWearMaterialApi public static void SwipeToRevealCard(androidx.wear.compose.material.SwipeToRevealAction action, androidx.wear.compose.foundation.RevealState revealState, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwipeToRevealAction? additionalAction, optional androidx.wear.compose.material.SwipeToRevealAction? undoAction, optional androidx.wear.compose.material.SwipeToRevealActionColors colors, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.material.ExperimentalWearMaterialApi public static void SwipeToRevealChip(androidx.wear.compose.material.SwipeToRevealAction action, androidx.wear.compose.foundation.RevealState revealState, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwipeToRevealAction? additionalAction, optional androidx.wear.compose.material.SwipeToRevealAction? undoAction, optional androidx.wear.compose.material.SwipeToRevealActionColors colors, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
   @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeableDefaults {
     method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getAnimationSpec();
     method public float getVelocityThreshold();
diff --git a/wear/compose/compose-material/api/restricted_current.txt b/wear/compose/compose-material/api/restricted_current.txt
index c1b45d8..099285e 100644
--- a/wear/compose/compose-material/api/restricted_current.txt
+++ b/wear/compose/compose-material/api/restricted_current.txt
@@ -207,9 +207,9 @@
   }
 
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class FractionalThreshold implements androidx.wear.compose.material.ThresholdConfig {
-    ctor public FractionalThreshold(float fraction);
+    ctor public FractionalThreshold(@FloatRange(from=0.0, to=1.0) float fraction);
     method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
-    method public androidx.wear.compose.material.FractionalThreshold copy(float fraction);
+    method public androidx.wear.compose.material.FractionalThreshold copy(@FloatRange(from=0.0, to=1.0) float fraction);
   }
 
   public final class HorizontalPageIndicatorKt {
@@ -326,10 +326,10 @@
   }
 
   public final class PickerKt {
-    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
-    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
-    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
-    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+    method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
     method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerState rememberPickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
   }
 
@@ -412,10 +412,10 @@
   }
 
   @androidx.compose.runtime.Stable public interface PositionIndicatorState {
-    method public float getPositionFraction();
-    method public float sizeFraction(float scrollableContainerSizePx);
-    method public int visibility(float scrollableContainerSizePx);
-    property public abstract float positionFraction;
+    method @FloatRange(from=0.0, to=1.0) public float getPositionFraction();
+    method @FloatRange(from=0.0, to=1.0) public float sizeFraction(@FloatRange(from=0.0) float scrollableContainerSizePx);
+    method public int visibility(@FloatRange(from=0.0) float scrollableContainerSizePx);
+    property @FloatRange(from=0.0, to=1.0) public abstract float positionFraction;
   }
 
   @kotlin.jvm.JvmInline public final value class PositionIndicatorVisibility {
@@ -441,7 +441,7 @@
 
   public final class ProgressIndicatorKt {
     method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
-    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional float endAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
+    method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(@FloatRange(from=0.0, to=1.0) float progress, optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional float endAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
   }
 
   @androidx.compose.runtime.Stable public interface RadioButtonColors {
@@ -455,7 +455,7 @@
   }
 
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class ResistanceConfig {
-    ctor public ResistanceConfig(float basis, optional float factorAtMin, optional float factorAtMax);
+    ctor public ResistanceConfig(@FloatRange(from=0.0, fromInclusive=false) float basis, optional @FloatRange(from=0.0) float factorAtMin, optional @FloatRange(from=0.0) float factorAtMax);
     method public float computeResistance(float overflow);
     method public float getBasis();
     method public float getFactorAtMax();
@@ -514,9 +514,9 @@
   }
 
   @Deprecated @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
-    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
-    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
-    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
+    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+    method @Deprecated public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
   }
 
   @Deprecated public sealed interface ScalingLazyListLayoutInfo {
@@ -581,20 +581,20 @@
   }
 
   @Deprecated @androidx.compose.runtime.Stable public interface ScalingParams {
-    method @Deprecated public float getEdgeAlpha();
-    method @Deprecated public float getEdgeScale();
-    method @Deprecated public float getMaxElementHeight();
-    method @Deprecated public float getMaxTransitionArea();
-    method @Deprecated public float getMinElementHeight();
-    method @Deprecated public float getMinTransitionArea();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getEdgeAlpha();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getEdgeScale();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMaxElementHeight();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMaxTransitionArea();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMinElementHeight();
+    method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMinTransitionArea();
     method @Deprecated public androidx.compose.animation.core.Easing getScaleInterpolator();
     method @Deprecated public int resolveViewportVerticalOffset(long viewportConstraints);
-    property @Deprecated public abstract float edgeAlpha;
-    property @Deprecated public abstract float edgeScale;
-    property @Deprecated public abstract float maxElementHeight;
-    property @Deprecated public abstract float maxTransitionArea;
-    property @Deprecated public abstract float minElementHeight;
-    property @Deprecated public abstract float minTransitionArea;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float edgeAlpha;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float edgeScale;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float maxElementHeight;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float maxTransitionArea;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float minElementHeight;
+    property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float minTransitionArea;
     property @Deprecated public abstract androidx.compose.animation.core.Easing scaleInterpolator;
   }
 
@@ -645,7 +645,7 @@
   }
 
   @SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeProgress<T> {
-    ctor public SwipeProgress(T from, T to, float fraction);
+    ctor public SwipeProgress(T from, T to, @FloatRange(from=0.0, to=1.0) float fraction);
     method public float getFraction();
     method public T getFrom();
     method public T getTo();
@@ -694,6 +694,55 @@
     enum_constant public static final androidx.wear.compose.material.SwipeToDismissValue Dismissed;
   }
 
+  @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealAction {
+    ctor public SwipeToRevealAction(kotlin.jvm.functions.Function0<kotlin.Unit>? icon, kotlin.jvm.functions.Function0<kotlin.Unit>? label, androidx.compose.ui.Modifier modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public kotlin.jvm.functions.Function0<kotlin.Unit>? getIcon();
+    method public androidx.compose.foundation.interaction.MutableInteractionSource getInteractionSource();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit>? getLabel();
+    method public androidx.compose.ui.Modifier getModifier();
+    method public kotlin.jvm.functions.Function0<kotlin.Unit> getOnClick();
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit>? icon;
+    property public final androidx.compose.foundation.interaction.MutableInteractionSource interactionSource;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit>? label;
+    property public final androidx.compose.ui.Modifier modifier;
+    property public final kotlin.jvm.functions.Function0<kotlin.Unit> onClick;
+  }
+
+  @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealActionColors {
+    ctor public SwipeToRevealActionColors(long actionBackgroundColor, long actionContentColor, long additionalActionBackgroundColor, long additionalActionContentColor, long undoActionBackgroundColor, long undoActionContentColor);
+    method public long getActionBackgroundColor();
+    method public long getActionContentColor();
+    method public long getAdditionalActionBackgroundColor();
+    method public long getAdditionalActionContentColor();
+    method public long getUndoActionBackgroundColor();
+    method public long getUndoActionContentColor();
+    property public final long actionBackgroundColor;
+    property public final long actionContentColor;
+    property public final long additionalActionBackgroundColor;
+    property public final long additionalActionContentColor;
+    property public final long undoActionBackgroundColor;
+    property public final long undoActionContentColor;
+  }
+
+  @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealDefaults {
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction action(kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealActionColors actionColors(optional long actionBackgroundColor, optional long actionContentColor, optional long additionalActionBackgroundColor, optional long additionalActionContentColor, optional long undoActionBackgroundColor, optional long undoActionContentColor);
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction additionalAction(kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    method public androidx.compose.foundation.shape.RoundedCornerShape getCardActionShape();
+    method public androidx.compose.ui.graphics.vector.ImageVector getDelete();
+    method public androidx.compose.ui.graphics.vector.ImageVector getMoreOptions();
+    method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction undoAction(kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+    property public final androidx.compose.foundation.shape.RoundedCornerShape CardActionShape;
+    property public final androidx.compose.ui.graphics.vector.ImageVector Delete;
+    property public final androidx.compose.ui.graphics.vector.ImageVector MoreOptions;
+    field public static final androidx.wear.compose.material.SwipeToRevealDefaults INSTANCE;
+  }
+
+  public final class SwipeToRevealKt {
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.material.ExperimentalWearMaterialApi public static void SwipeToRevealCard(androidx.wear.compose.material.SwipeToRevealAction action, androidx.wear.compose.foundation.RevealState revealState, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwipeToRevealAction? additionalAction, optional androidx.wear.compose.material.SwipeToRevealAction? undoAction, optional androidx.wear.compose.material.SwipeToRevealActionColors colors, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.material.ExperimentalWearMaterialApi public static void SwipeToRevealChip(androidx.wear.compose.material.SwipeToRevealAction action, androidx.wear.compose.foundation.RevealState revealState, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwipeToRevealAction? additionalAction, optional androidx.wear.compose.material.SwipeToRevealAction? undoAction, optional androidx.wear.compose.material.SwipeToRevealActionColors colors, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+  }
+
   @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeableDefaults {
     method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getAnimationSpec();
     method public float getVelocityThreshold();
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/PlaceholderTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/PlaceholderTest.kt
index 2ce728d..55f9f33 100644
--- a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/PlaceholderTest.kt
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/PlaceholderTest.kt
@@ -54,13 +54,6 @@
             placeholderState = rememberPlaceholderState {
                 contentReady.value
             }
-            Chip(
-                modifier = Modifier.fillMaxWidth(),
-                content = {},
-                onClick = {},
-                colors = ChipDefaults.secondaryChipColors(),
-                border = ChipDefaults.chipBorder()
-            )
         }
 
         // For testing we need to manually manage the frame clock for the placeholder animation
@@ -77,19 +70,13 @@
     @OptIn(ExperimentalWearMaterialApi::class)
     @Test
     fun placeholder_initially_show_placeholder_transitions_correctly() {
-        var contentReady = false
+        lateinit var contentReady: MutableState<Boolean>
         lateinit var placeholderState: PlaceholderState
         rule.setContentWithTheme {
+            contentReady = remember { mutableStateOf(false) }
             placeholderState = rememberPlaceholderState {
-                contentReady
+                contentReady.value
             }
-            Chip(
-                modifier = Modifier.fillMaxWidth(),
-                content = {},
-                onClick = {},
-                colors = ChipDefaults.secondaryChipColors(),
-                border = ChipDefaults.chipBorder()
-            )
         }
 
         // For testing we need to manually manage the frame clock for the placeholder animation
@@ -99,12 +86,13 @@
         // ShowPlaceholder
         placeholderState.advanceFrameMillisAndCheckState(
             PLACEHOLDER_SHIMMER_GAP_BETWEEN_ANIMATION_LOOPS_MS,
-            PlaceholderStage.ShowPlaceholder)
+            PlaceholderStage.ShowPlaceholder
+        )
 
         // Change contentReady and confirm that state is now WipeOff
-        contentReady = true
+        contentReady.value = true
         placeholderState.advanceFrameMillisAndCheckState(
-            0L,
+            1L,
             PlaceholderStage.WipeOff
         )
 
@@ -209,18 +197,18 @@
                 expectedPlaceholderColor
             )
 
+        // Change contentReady and confirm that state is now WipeOff
         contentReady.value = true
+        placeholderState.advanceFrameMillisAndCheckState(
+            1L,
+            PlaceholderStage.WipeOff
+        )
 
-        // Advance the clock to the next placeholder animation loop and check for wipe-off mode
-        placeholderState
-            .advanceFrameMillisAndCheckState(
-                (PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS * 0.5f).toLong(),
-                PlaceholderStage.WipeOff
-            )
-
-        // Advance the clock to the next placeholder animation loop and check for show content mode
-        placeholderState
-            .advanceToNextPlaceholderAnimationLoopAndCheckStage(PlaceholderStage.ShowContent)
+        // Advance the clock by one cycle and check we have moved to ShowContent
+        placeholderState.advanceFrameMillisAndCheckState(
+            PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
+            PlaceholderStage.ShowContent
+        )
 
         rule.onNodeWithTag("test-item")
             .captureToImage()
@@ -269,7 +257,7 @@
         // Move the start of the next placeholder shimmer animation loop and them advance the
         // clock to show the shimmer.
         placeholderState.advanceFrameMillisAndCheckState(
-                (PLACEHOLDER_SHIMMER_DURATION_MS * 0.5f).toLong(),
+            (PLACEHOLDER_SHIMMER_DURATION_MS * 0.5f).toLong(),
             PlaceholderStage.ShowPlaceholder
         )
 
@@ -279,11 +267,12 @@
             .captureToImage()
             .assertDoesNotContainColor(expectedBackgroundColor)
 
-        // Prepare to start to wipe off and show contents.
+        // Change contentReady and confirm that state is now WipeOff
         contentReady.value = true
-
-        placeholderState
-            .advanceToNextPlaceholderAnimationLoopAndCheckStage(PlaceholderStage.WipeOff)
+        placeholderState.advanceFrameMillisAndCheckState(
+            1L,
+            PlaceholderStage.WipeOff
+        )
 
         // Check the background color is correct
         rule.onNodeWithTag("test-item")
@@ -292,8 +281,11 @@
                 expectedBackgroundColor, 80f
             )
 
-        placeholderState
-            .advanceToNextPlaceholderAnimationLoopAndCheckStage(PlaceholderStage.ShowContent)
+        // Advance the clock by one cycle and check we have moved to ShowContent
+        placeholderState.advanceFrameMillisAndCheckState(
+            PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
+            PlaceholderStage.ShowContent
+        )
 
         // Check that the shimmer is no longer visible
         rule.onNodeWithTag("test-item")
@@ -352,11 +344,12 @@
                 expectedBackgroundColor
             )
 
-        // Prepare to start to wipe off and show contents.
+        // Change contentReady and confirm that state is now WipeOff
         contentReady.value = true
-
-        placeholderState
-            .advanceToNextPlaceholderAnimationLoopAndCheckStage(PlaceholderStage.WipeOff)
+        placeholderState.advanceFrameMillisAndCheckState(
+            1L,
+            PlaceholderStage.WipeOff
+        )
 
         // Check that placeholder background is still visible
         rule.onNodeWithTag("test-item")
@@ -434,10 +427,12 @@
 
         // Trigger move to WipeOff stage
         placeholderState.value?.advanceFrameMillisAndCheckState(
-            1, PlaceholderStage.WipeOff)
+            1, PlaceholderStage.WipeOff
+        )
 
         placeholderState.value?.advanceFrameMillisAndCheckState(
-            PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS, PlaceholderStage.ShowContent)
+            PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS, PlaceholderStage.ShowContent
+        )
     }
 
     @RequiresApi(Build.VERSION_CODES.O)
@@ -458,6 +453,7 @@
             Chip(
                 modifier = Modifier
                     .testTag("test-item")
+                    .fillMaxWidth()
                     .placeholderShimmer(placeholderState),
                 content = {},
                 onClick = {},
@@ -480,14 +476,16 @@
                 expectedPlaceholderBackgroundColor
             )
 
+        // Change contentReady and confirm that state is now WipeOff
         contentReady.value = true
-
-        // Trigger move to WipeOff stage
         placeholderState.advanceFrameMillisAndCheckState(
-            1, PlaceholderStage.WipeOff)
+            1L, PlaceholderStage.WipeOff
+        )
 
         placeholderState.advanceFrameMillisAndCheckState(
-            PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS, PlaceholderStage.ShowContent)
+            PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
+            PlaceholderStage.ShowContent
+        )
 
         // Check the placeholder background has gone and that we can see the chips background
         rule.onNodeWithTag("test-item")
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToRevealTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToRevealTest.kt
new file mode 100644
index 0000000..e30df01
--- /dev/null
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToRevealTest.kt
@@ -0,0 +1,377 @@
+/*
+ * 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.wear.compose.material
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
+import androidx.wear.compose.foundation.RevealState
+import androidx.wear.compose.foundation.RevealValue
+import androidx.wear.compose.foundation.rememberRevealState
+import junit.framework.TestCase.assertEquals
+import org.junit.Rule
+import org.junit.Test
+
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
+class SwipeToRevealActionTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun supports_testTag_onChip() {
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault(modifier = Modifier.testTag(TEST_TAG))
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertExists()
+    }
+
+    @Test
+    fun supports_testTag_onCard() {
+        rule.setContentWithTheme {
+            swipeToRevealCardDefault(modifier = Modifier.testTag(TEST_TAG))
+        }
+
+        rule.onNodeWithTag(TEST_TAG).assertExists()
+    }
+
+    @Test
+    fun supports_testTag_onContent_onChip() {
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault()
+        }
+
+        rule.onNodeWithTag(CONTENT_TAG).assertExists()
+    }
+
+    @Test
+    fun supports_testTag_onContent_onCard() {
+        rule.setContentWithTheme {
+            swipeToRevealCardDefault()
+        }
+
+        rule.onNodeWithTag(CONTENT_TAG).assertExists()
+    }
+
+    @Test
+    fun whenNotRevealed_actionsDoNotExist_inChip() {
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault()
+        }
+
+        rule.onNodeWithTag(ACTION_TAG).assertDoesNotExist()
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertDoesNotExist()
+        rule.onNodeWithTag(UNDO_ACTION_TAG).assertDoesNotExist()
+    }
+
+    @Test
+    fun whenNotRevealed_actionsDoNotExist_inCard() {
+        rule.setContentWithTheme {
+            swipeToRevealCardDefault()
+        }
+
+        rule.onNodeWithTag(ACTION_TAG).assertDoesNotExist()
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertDoesNotExist()
+        rule.onNodeWithTag(UNDO_ACTION_TAG).assertDoesNotExist()
+    }
+
+    @Test
+    fun whenRevealing_actionsExist_inChip() {
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+            )
+        }
+        rule.onNodeWithTag(ACTION_TAG).assertExists()
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertExists()
+    }
+
+    @Test
+    fun whenRevealing_actionsExist_inCard() {
+        rule.setContentWithTheme {
+            swipeToRevealCardDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+            )
+        }
+        rule.onNodeWithTag(ACTION_TAG).assertExists()
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertExists()
+    }
+
+    @Test
+    fun whenRevealed_undoActionExists_inChip() {
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+            )
+        }
+
+        rule.onNodeWithTag(UNDO_ACTION_TAG).assertExists()
+    }
+
+    @Test
+    fun whenRevealed_undoActionExists_inCard() {
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+            )
+        }
+
+        rule.onNodeWithTag(UNDO_ACTION_TAG).assertExists()
+    }
+
+    @Test
+    fun whenRevealed_actionsDoesNotExists_inChip() {
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+            )
+        }
+
+        rule.onNodeWithTag(ACTION_TAG).assertDoesNotExist()
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertDoesNotExist()
+    }
+
+    @Test
+    fun whenRevealed_actionsDoesNotExists_inCard() {
+        rule.setContentWithTheme {
+            swipeToRevealCardDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+            )
+        }
+
+        rule.onNodeWithTag(ACTION_TAG).assertDoesNotExist()
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertDoesNotExist()
+    }
+
+    @Test
+    fun onActionClick_triggersOnClick_forChip() {
+        var clicked = false
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing),
+                action = createAction(
+                    onClick = { clicked = true }
+                )
+            )
+        }
+
+        rule.onNodeWithTag(ACTION_TAG).performClick()
+        rule.runOnIdle { assertEquals(true, clicked) }
+    }
+
+    @Test
+    fun onAdditionalActionClick_triggersOnClick_forChip() {
+        var clicked = false
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing),
+                additionalAction = createAdditionalAction(
+                    onClick = { clicked = true }
+                )
+            )
+        }
+
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).performClick()
+        rule.runOnIdle { assertEquals(true, clicked) }
+    }
+
+    @Test
+    fun onActionClick_stateChangesToRevealed_forChip() {
+        lateinit var revealState: RevealState
+        rule.setContentWithTheme {
+            revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+            swipeToRevealChipDefault(
+                revealState = revealState,
+            )
+        }
+
+        rule.onNodeWithTag(ACTION_TAG).performClick()
+        rule.runOnIdle { assertEquals(RevealValue.Revealed, revealState.currentValue) }
+    }
+
+    @Test
+    fun onAdditionalActionClick_stateChangesToRevealed_forChip() {
+        lateinit var revealState: RevealState
+        rule.setContentWithTheme {
+            revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+            swipeToRevealChipDefault(
+                revealState = revealState,
+            )
+        }
+
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).performClick()
+        rule.runOnIdle { assertEquals(RevealValue.Revealed, revealState.currentValue) }
+    }
+
+    @Test
+    fun onUndoActionClick_stateChangesToCovered_forChip() {
+        lateinit var revealState: RevealState
+        rule.setContentWithTheme {
+            revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+            swipeToRevealChipDefault(
+                revealState = revealState,
+            )
+        }
+
+        rule.onNodeWithTag(UNDO_ACTION_TAG).performClick()
+        rule.runOnIdle { assertEquals(RevealValue.Covered, revealState.currentValue) }
+    }
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun verifyActionColors() {
+        var actionColor = Color.Yellow
+        var additionalActionColor = Color.Green
+        rule.setContentWithTheme {
+            actionColor = MaterialTheme.colors.error
+            additionalActionColor = MaterialTheme.colors.surface
+            swipeToRevealChipDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+            )
+        }
+
+        rule.onNodeWithTag(ACTION_TAG)
+            .captureToImage()
+            .assertContainsColor(actionColor, 50.0f)
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG)
+            .captureToImage()
+            .assertContainsColor(additionalActionColor)
+    }
+
+    @RequiresApi(Build.VERSION_CODES.O)
+    @Test
+    fun canOverrideActionColors() {
+        val overrideActionColor = Color.Yellow
+        val overrideAdditionalActionColor = Color.Green
+        rule.setContentWithTheme {
+            swipeToRevealChipDefault(
+                revealState = rememberRevealState(initialValue = RevealValue.Revealing),
+                colors = SwipeToRevealDefaults.actionColors(
+                    actionBackgroundColor = overrideActionColor,
+                    additionalActionBackgroundColor = overrideAdditionalActionColor
+                )
+            )
+        }
+
+        rule.onNodeWithTag(ACTION_TAG)
+            .captureToImage()
+            .assertContainsColor(overrideActionColor, 50.0f)
+        rule.onNodeWithTag(ADDITIONAL_ACTION_TAG)
+            .captureToImage()
+            .assertContainsColor(overrideAdditionalActionColor, 50.0f)
+    }
+
+    @Composable
+    private fun swipeToRevealChipDefault(
+        modifier: Modifier = Modifier,
+        revealState: RevealState = rememberRevealState(),
+        action: SwipeToRevealAction = createAction(),
+        additionalAction: SwipeToRevealAction = createAdditionalAction(),
+        undoAction: SwipeToRevealAction = createUndoAction(),
+        colors: SwipeToRevealActionColors = SwipeToRevealDefaults.actionColors(),
+        content: @Composable () -> Unit = { createContent() }
+    ) {
+        SwipeToRevealChip(
+            modifier = modifier,
+            revealState = revealState,
+            action = action,
+            additionalAction = additionalAction,
+            undoAction = undoAction,
+            colors = colors,
+            content = content
+        )
+    }
+
+    @Composable
+    private fun swipeToRevealCardDefault(
+        modifier: Modifier = Modifier,
+        revealState: RevealState = rememberRevealState(),
+        action: SwipeToRevealAction = createAction(),
+        additionalAction: SwipeToRevealAction = createAdditionalAction(),
+        undoAction: SwipeToRevealAction = createUndoAction(),
+        colors: SwipeToRevealActionColors = SwipeToRevealDefaults.actionColors(),
+        content: @Composable () -> Unit = { createContent() }
+    ) {
+        SwipeToRevealCard(
+            modifier = modifier,
+            revealState = revealState,
+            action = action,
+            additionalAction = additionalAction,
+            undoAction = undoAction,
+            colors = colors,
+            content = content
+        )
+    }
+
+    @Composable
+    private fun createAction(
+        icon: @Composable () -> Unit = { Icon(SwipeToRevealDefaults.Delete, "Delete") },
+        label: @Composable () -> Unit = { Text("Clear") },
+        modifier: Modifier = Modifier,
+        onClick: () -> Unit = {},
+    ): SwipeToRevealAction = SwipeToRevealDefaults.action(
+        icon = icon,
+        label = label,
+        modifier = modifier.testTag(ACTION_TAG),
+        onClick = onClick
+    )
+
+    @Composable
+    private fun createAdditionalAction(
+        icon: @Composable () -> Unit = { Icon(SwipeToRevealDefaults.MoreOptions, "More Options") },
+        modifier: Modifier = Modifier,
+        onClick: () -> Unit = {},
+    ): SwipeToRevealAction = SwipeToRevealDefaults.additionalAction(
+        icon = icon,
+        modifier = modifier.testTag(ADDITIONAL_ACTION_TAG),
+        onClick = onClick
+    )
+
+    @Composable
+    private fun createUndoAction(
+        label: @Composable () -> Unit = { Text("Undo") },
+        modifier: Modifier = Modifier
+    ) = SwipeToRevealDefaults.undoAction(
+        label = label,
+        modifier = modifier.testTag(UNDO_ACTION_TAG)
+    )
+
+    @Composable
+    private fun createContent(
+        modifier: Modifier = Modifier
+    ) = Box(modifier = modifier
+        .fillMaxWidth()
+        .height(50.dp)
+        .testTag(CONTENT_TAG))
+
+    private val CONTENT_TAG = "Content"
+    private val ACTION_TAG = "Action"
+    private val ADDITIONAL_ACTION_TAG = "AdditionalAction"
+    private val UNDO_ACTION_TAG = "UndoAction"
+}
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ContentAlpha.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ContentAlpha.kt
index 314e312..2f6e8b5 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ContentAlpha.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ContentAlpha.kt
@@ -15,6 +15,7 @@
  */
 package androidx.wear.compose.material
 
+import androidx.annotation.FloatRange
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ProvidableCompositionLocal
 import androidx.compose.runtime.compositionLocalOf
@@ -69,9 +70,9 @@
      */
     @Composable
     private fun contentAlpha(
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         highContrastAlpha: Float,
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         lowContrastAlpha: Float
     ): Float {
         val contentColor = LocalContentColor.current
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Picker.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Picker.kt
index 2aaa04b..6587a21 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Picker.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Picker.kt
@@ -15,6 +15,7 @@
  */
 package androidx.wear.compose.material
 
+import androidx.annotation.FloatRange
 import androidx.compose.animation.core.CubicBezierEasing
 import androidx.compose.animation.core.DecayAnimationSpec
 import androidx.compose.animation.core.Easing
@@ -59,11 +60,11 @@
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
-import androidx.wear.compose.foundation.lazy.AutoCenteringParams as AutoCenteringParams
-import androidx.wear.compose.foundation.lazy.ScalingLazyColumn as ScalingLazyColumn
-import androidx.wear.compose.foundation.lazy.ScalingLazyColumnDefaults as ScalingLazyColumnDefaults
-import androidx.wear.compose.foundation.lazy.ScalingLazyListState as ScalingLazyListState
-import androidx.wear.compose.foundation.lazy.ScalingParams as ScalingParams
+import androidx.wear.compose.foundation.lazy.AutoCenteringParams
+import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
+import androidx.wear.compose.foundation.lazy.ScalingLazyColumnDefaults
+import androidx.wear.compose.foundation.lazy.ScalingLazyListState
+import androidx.wear.compose.foundation.lazy.ScalingParams
 import kotlinx.coroutines.launch
 
 /**
@@ -120,7 +121,7 @@
     onSelected: () -> Unit = {},
     scalingParams: ScalingParams = PickerDefaults.defaultScalingParams(),
     separation: Dp = 0.dp,
-    /* @FloatRange(from = 0.0, to = 0.5) */
+    @FloatRange(from = 0.0, to = 0.5)
     gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
     gradientColor: Color = MaterialTheme.colors.background,
     flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state),
@@ -245,7 +246,7 @@
     onSelected: () -> Unit = {},
     scalingParams: androidx.wear.compose.material.ScalingParams = PickerDefaults.scalingParams(),
     separation: Dp = 0.dp,
-    /* @FloatRange(from = 0.0, to = 0.5) */
+    @FloatRange(from = 0.0, to = 0.5)
     gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
     gradientColor: Color = MaterialTheme.colors.background,
     flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state),
@@ -322,7 +323,7 @@
     onSelected: () -> Unit = {},
     scalingParams: androidx.wear.compose.material.ScalingParams = PickerDefaults.scalingParams(),
     separation: Dp = 0.dp,
-    /* @FloatRange(from = 0.0, to = 0.5) */
+    @FloatRange(from = 0.0, to = 0.5)
     gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
     gradientColor: Color = MaterialTheme.colors.background,
     flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state),
@@ -389,7 +390,7 @@
     readOnlyLabel: @Composable (BoxScope.() -> Unit)? = null,
     scalingParams: androidx.wear.compose.material.ScalingParams = PickerDefaults.scalingParams(),
     separation: Dp = 0.dp,
-    /* @FloatRange(from = 0.0, to = 0.5) */
+    @FloatRange(from = 0.0, to = 0.5)
     gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
     gradientColor: Color = MaterialTheme.colors.background,
     flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state),
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/PositionIndicator.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/PositionIndicator.kt
index d5da8bc..77f29fb 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/PositionIndicator.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/PositionIndicator.kt
@@ -16,6 +16,7 @@
 
 package androidx.wear.compose.material
 
+import androidx.annotation.FloatRange
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.AnimationVector
@@ -127,9 +128,7 @@
      * Position of the indicator in the range [0f,1f]. 0f means it is at the top|start, 1f means
      * it is positioned at the bottom|end.
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val positionFraction: Float
 
     /**
@@ -139,10 +138,11 @@
      * in pixels depending on orientation of the indicator, (height for vertical, width for
      * horizontal)
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
-    fun sizeFraction(scrollableContainerSizePx: Float): Float
+    @FloatRange(from = 0.0, to = 1.0)
+    fun sizeFraction(
+        @FloatRange(from = 0.0)
+        scrollableContainerSizePx: Float
+    ): Float
 
     /**
      * Should we show the Position Indicator
@@ -151,7 +151,10 @@
      * in pixels depending on orientation of the indicator, (height for vertical, width for
      * horizontal)
      */
-    fun visibility(scrollableContainerSizePx: Float): PositionIndicatorVisibility
+    fun visibility(
+        @FloatRange(from = 0.0)
+        scrollableContainerSizePx: Float
+    ): PositionIndicatorVisibility
 }
 
 /**
@@ -223,9 +226,11 @@
  * @param reverseDirection Reverses direction of PositionIndicator if true
  */
 @Suppress("DEPRECATION")
-@Deprecated("This overload is provided for backwards compatibility with Compose for Wear OS 1.1." +
+@Deprecated(
+    "This overload is provided for backwards compatibility with Compose for Wear OS 1.1." +
         "A newer overload is available which uses ScalingLazyListState from " +
-        "androidx.wear.compose.foundation.lazy package", level = DeprecationLevel.WARNING)
+        "androidx.wear.compose.foundation.lazy package", level = DeprecationLevel.WARNING
+)
 @Composable
 public fun PositionIndicator(
     scalingLazyListState: androidx.wear.compose.material.ScalingLazyListState,
@@ -782,7 +787,7 @@
         if (state.layoutInfo.visibleItemsInfo.isEmpty()) return 0f
         val firstItem = state.layoutInfo.visibleItemsInfo.first()
         val firstItemStartOffset = firstItem.startOffset(state.layoutInfo.anchorType)
-        val viewportStartOffset = - (state.layoutInfo.viewportSize.height / 2f)
+        val viewportStartOffset = -(state.layoutInfo.viewportSize.height / 2f)
         // Coerce item size to at least 1 to avoid divide by zero for zero height items
         val firstItemInvisibleFraction =
             ((viewportStartOffset - firstItemStartOffset) /
@@ -866,7 +871,7 @@
         if (state.layoutInfo.visibleItemsInfo.isEmpty()) return 0f
         val firstItem = state.layoutInfo.visibleItemsInfo.first()
         val firstItemStartOffset = firstItem.startOffset(state.anchorType.value!!)
-        val viewportStartOffset = - (state.viewportHeightPx.value!! / 2f)
+        val viewportStartOffset = -(state.viewportHeightPx.value!! / 2f)
         // Coerce item size to at least 1 to avoid divide by zero for zero height items
         val firstItemInvisibleFraction =
             ((viewportStartOffset - firstItemStartOffset) /
@@ -1122,7 +1127,8 @@
         modifier
             .transparentSizeModifier(size)
             .absoluteOffset { -offset() }, content = content,
-        contentAlignment = AbsoluteAlignment.TopLeft)
+        contentAlignment = AbsoluteAlignment.TopLeft
+    )
 }
 
 // Sets the size of this element, but lets the child measure using the constraints
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ProgressIndicator.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ProgressIndicator.kt
index 2b0ebbe..c05d7b5 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ProgressIndicator.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ProgressIndicator.kt
@@ -1,5 +1,6 @@
 package androidx.wear.compose.material
 
+import androidx.annotation.FloatRange
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.CubicBezierEasing
 import androidx.compose.animation.core.LinearEasing
@@ -78,7 +79,7 @@
  */
 @Composable
 public fun CircularProgressIndicator(
-    /* @FloatRange(fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0) */
+    @FloatRange(from = 0.0, to = 1.0)
     progress: Float,
     modifier: Modifier = Modifier,
     startAngle: Float = 270f,
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
index 382be50..b3abd6e 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
@@ -18,6 +18,7 @@
 
 package androidx.wear.compose.material
 
+import androidx.annotation.FloatRange
 import androidx.compose.animation.core.Easing
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.lazy.LazyListItemInfo
@@ -104,9 +105,7 @@
      * scaled, e.g. at the edge of the viewport. A value between [0f,1f], so a value of 0.2f
      * means to scale an item to 20% of its normal size.
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val edgeScale: Float
 
     /**
@@ -114,9 +113,7 @@
      * when closest to the edge of the screen. A value between [0f,1f], so a value of
      * 0.2f means to set the alpha of an item to 20% of its normal value.
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val edgeAlpha: Float
 
     /**
@@ -126,9 +123,7 @@
      * will be treated as if [maxElementHeight]. Must be greater than or equal to
      * [minElementHeight].
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val minElementHeight: Float
 
     /**
@@ -138,9 +133,7 @@
      * will be treated as if [maxElementHeight]. Must be greater than or equal to
      * [minElementHeight].
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val maxElementHeight: Float
 
     /**
@@ -157,9 +150,7 @@
      * list items exist. Depending on the size of the list item the specific point in the area is
      * calculated.
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val minTransitionArea: Float
 
     /**
@@ -176,9 +167,7 @@
      * list items exist. Depending on the size of the list item the specific point in the area is
      * calculated.
      */
-//    @FloatRange(
-//        fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-//    )
+    @get:FloatRange(from = 0.0, to = 1.0)
     val maxTransitionArea: Float
 
     /**
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyListItemScope.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyListItemScope.kt
index d346a0b..2f2c6fad 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyListItemScope.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyListItemScope.kt
@@ -17,6 +17,7 @@
 
 package androidx.wear.compose.material
 
+import androidx.annotation.FloatRange
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
@@ -46,7 +47,7 @@
      * measured with [Constraints.Infinity] as the constraints for the main axis.
      */
     fun Modifier.fillParentMaxSize(
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         fraction: Float = 1f
     ): Modifier
 
@@ -61,7 +62,7 @@
      * items are measured with [Constraints.Infinity] as the constraints for the main axis.
      */
     fun Modifier.fillParentMaxWidth(
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         fraction: Float = 1f
     ): Modifier
 
@@ -76,7 +77,7 @@
      * items are measured with [Constraints.Infinity] as the constraints for the main axis.
      */
     fun Modifier.fillParentMaxHeight(
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         fraction: Float = 1f
     ): Modifier
 }
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToReveal.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToReveal.kt
new file mode 100644
index 0000000..59b4635
--- /dev/null
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToReveal.kt
@@ -0,0 +1,537 @@
+/*
+ * 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.wear.compose.material
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Delete
+import androidx.compose.material.icons.outlined.MoreVert
+import androidx.compose.material.ripple.rememberRipple
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
+import androidx.wear.compose.foundation.RevealScope
+import androidx.wear.compose.foundation.RevealState
+import androidx.wear.compose.foundation.RevealValue
+import androidx.wear.compose.foundation.SwipeToReveal
+import kotlin.math.abs
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * [SwipeToReveal] Material composable for Chips. This provides the default style for consistency.
+ *
+ * @see [SwipeToReveal]
+ * @param action An [SwipeToRevealAction] object to describe the primary action when swiping. See
+ * [SwipeToRevealDefaults.action].
+ * @param revealState [RevealState] of the [SwipeToReveal]
+ * @param modifier [Modifier] to be applied on the composable
+ * @param additionalAction An [SwipeToRevealAction] object to describe the contents of addition action.
+ * See [SwipeToRevealDefaults.additionalAction]
+ * @param undoAction An [SwipeToRevealAction] object to describe the contents of undo action. See
+ * [SwipeToRevealDefaults.undoAction].
+ * @param colors An instance of [SwipeToRevealActionColors] to describe the colors of actions. See
+ * [SwipeToRevealDefaults.actionColors].
+ * @param shape The shape of action and additional action composables. Recommended shape for chips
+ * is [Shapes.small].
+ * @param content The initial content shown prior to the swipe-to-reveal gesture.
+ */
+@ExperimentalWearMaterialApi
+@OptIn(ExperimentalWearFoundationApi::class)
+@Composable
+public fun SwipeToRevealChip(
+    action: SwipeToRevealAction,
+    revealState: RevealState,
+    modifier: Modifier = Modifier,
+    additionalAction: SwipeToRevealAction? = null,
+    undoAction: SwipeToRevealAction? = null,
+    colors: SwipeToRevealActionColors = SwipeToRevealDefaults.actionColors(),
+    shape: Shape = MaterialTheme.shapes.small,
+    content: @Composable () -> Unit
+) {
+    SwipeToRevealComponent(
+        action = action,
+        revealState = revealState,
+        modifier = modifier,
+        additionalAction = additionalAction,
+        undoAction = undoAction,
+        colors = colors,
+        shape = shape,
+        content = content
+    )
+}
+
+/**
+ * [SwipeToReveal] Material composable for Cards. This provides the default style for consistency.
+ *
+ * @see [SwipeToReveal]
+ * @param action An [SwipeToRevealAction] object to describe the primary action when swiping. See
+ * [SwipeToRevealDefaults.action]
+ * @param revealState [RevealState] of the [SwipeToReveal]
+ * @param modifier [Modifier] to be applied on the composable
+ * @param additionalAction An [SwipeToRevealAction] object to describe the contents of addition action
+ * @param undoAction An [SwipeToRevealAction] object to describe the contents of undo action
+ * @param colors An instance of [SwipeToRevealActionColors] to describe the colors of actions. See
+ * [SwipeToRevealDefaults.actionColors].
+ * @param shape The shape of action and additional action composables. Recommended shape for cards
+ * is [SwipeToRevealDefaults.CardActionShape].
+ * @param content The initial content shown prior to the swipe-to-reveal gesture.
+ */
+@ExperimentalWearMaterialApi
+@OptIn(ExperimentalWearFoundationApi::class)
+@Composable
+public fun SwipeToRevealCard(
+    action: SwipeToRevealAction,
+    revealState: RevealState,
+    modifier: Modifier = Modifier,
+    additionalAction: SwipeToRevealAction? = null,
+    undoAction: SwipeToRevealAction? = null,
+    colors: SwipeToRevealActionColors = SwipeToRevealDefaults.actionColors(),
+    shape: Shape = SwipeToRevealDefaults.CardActionShape,
+    content: @Composable () -> Unit
+) {
+    SwipeToRevealComponent(
+        action = action,
+        revealState = revealState,
+        modifier = modifier,
+        additionalAction = additionalAction,
+        undoAction = undoAction,
+        colors = colors,
+        shape = shape,
+        content = content
+    )
+}
+
+/**
+ * Defaults for Material [SwipeToReveal].
+ */
+@ExperimentalWearMaterialApi
+public object SwipeToRevealDefaults {
+    /**
+     * Recommended shape for [SwipeToReveal] actions when used with [Card].
+     */
+    public val CardActionShape = RoundedCornerShape(40.dp)
+
+    /**
+     * Colors to be used with different actions in [SwipeToReveal].
+     *
+     * @param actionBackgroundColor The background color (color of the shape) of the action
+     * @param actionContentColor The content color (text and icon) of the action
+     * @param additionalActionBackgroundColor The background color (color of the shape) of the
+     * additional action
+     * @param additionalActionContentColor The content color (text and icon) of the additional
+     * action
+     * @param undoActionBackgroundColor The background color (color of the shape) of the undo action
+     * @param undoActionContentColor The content color (text) of the undo action
+     */
+    @Composable
+    public fun actionColors(
+        actionBackgroundColor: Color = MaterialTheme.colors.error,
+        actionContentColor: Color = MaterialTheme.colors.onError,
+        additionalActionBackgroundColor: Color = MaterialTheme.colors.surface,
+        additionalActionContentColor: Color = MaterialTheme.colors.onSurface,
+        undoActionBackgroundColor: Color = MaterialTheme.colors.surface,
+        undoActionContentColor: Color = MaterialTheme.colors.onSurface
+    ): SwipeToRevealActionColors {
+        return SwipeToRevealActionColors(
+            actionBackgroundColor = actionBackgroundColor,
+            actionContentColor = actionContentColor,
+            additionalActionBackgroundColor = additionalActionBackgroundColor,
+            additionalActionContentColor = additionalActionContentColor,
+            undoActionBackgroundColor = undoActionBackgroundColor,
+            undoActionContentColor = undoActionContentColor
+        )
+    }
+
+    /**
+     * Creates a new [SwipeToRevealAction] instance for the primary action parameter of [SwipeToRevealChip] and
+     * [SwipeToRevealCard]. The default behaviour of this action is to animate to
+     * [RevealValue.Revealed] and execute the [onClick] parameter. To override, consider using
+     * [Modifier.clickable].
+     *
+     * @param icon The icon that will be displayed initially on the action
+     * @param label The text that will be displayed on the expanded action
+     * @param modifier [Modifier] to be applied on this action composable
+     * @param interactionSource The [MutableInteractionSource] representing the stream of
+     * interactions with this action.
+     * @param onClick Called when this action is clicked.
+     */
+    @Composable
+    public fun action(
+        icon: @Composable () -> Unit,
+        label: @Composable () -> Unit,
+        modifier: Modifier = Modifier,
+        interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+        onClick: () -> Unit = {}
+    ): SwipeToRevealAction {
+        return SwipeToRevealAction(
+            icon = icon,
+            label = label,
+            modifier = modifier,
+            interactionSource = interactionSource,
+            onClick = onClick
+        )
+    }
+
+    /**
+     * Creates a new [SwipeToRevealAction] instance for the additional action of [SwipeToRevealChip] and
+     * [SwipeToRevealCard]. The default behaviour of this action is to animate to
+     * [RevealValue.Revealed] and execute the [onClick] parameter. To override, consider using
+     * [Modifier.clickable].
+     *
+     * @param icon The icon that will be displayed initially on the screen
+     * @param modifier [Modifier] to be applied on this action composable
+     * @param interactionSource The [MutableInteractionSource] representing the stream of
+     * interactions with this action.
+     * @param onClick Called when this action is clicked.
+     */
+    @Composable
+    public fun additionalAction(
+        icon: @Composable () -> Unit,
+        modifier: Modifier = Modifier,
+        interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+        onClick: () -> Unit = {}
+    ): SwipeToRevealAction {
+        return SwipeToRevealAction(
+            icon = icon,
+            label = null,
+            modifier = modifier,
+            interactionSource = interactionSource,
+            onClick = onClick
+        )
+    }
+
+    /**
+     * Creates a new [SwipeToRevealAction] instance for the undo action of [SwipeToRevealChip] and
+     * [SwipeToRevealCard]. The default behaviour of this action is to snap to
+     * [RevealValue.Covered] and execute the [onClick] parameter. To override, consider using
+     * [Modifier.clickable].
+     *
+     * @param label The text that will be displayed on the undo action composable
+     * @param modifier [Modifier] to be applied on this action composable
+     * @param interactionSource The [MutableInteractionSource] representing the stream of
+     * interactions with this action.
+     * @param onClick Called when this action is clicked.
+     */
+    @Composable
+    public fun undoAction(
+        label: @Composable () -> Unit,
+        modifier: Modifier = Modifier,
+        interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+        onClick: () -> Unit = {}
+    ): SwipeToRevealAction {
+        return SwipeToRevealAction(
+            icon = null,
+            label = label,
+            modifier = modifier,
+            interactionSource = interactionSource,
+            onClick = onClick
+        )
+    }
+
+    /**
+     * [ImageVector] for delete icon, often used for the primary action.
+     */
+    public val Delete = Icons.Outlined.Delete
+
+    /**
+     * [ImageVector] for more options icon, often used for the additional action.
+     */
+    public val MoreOptions = Icons.Outlined.MoreVert
+
+    internal val UndoButtonHorizontalPadding = 14.dp
+    internal val UndoButtonVerticalPadding = 6.dp
+    internal val ActionMaxHeight = 84.dp
+}
+
+/**
+ * A class representing the colors applied in [SwipeToReveal] actions.
+ *
+ * @param actionBackgroundColor Color of the shape (background)
+ * @param actionContentColor Color of icon or text used in the action
+ * @param additionalActionBackgroundColor Color of the additional action shape (background)
+ * @param additionalActionContentColor Color of the icon or text used in the additional action
+ * @param undoActionBackgroundColor Color of the undo action shape (background)
+ * @param undoActionContentColor Color of the icon or text used in the undo action
+ */
+@ExperimentalWearMaterialApi
+public class SwipeToRevealActionColors constructor(
+    val actionBackgroundColor: Color,
+    val actionContentColor: Color,
+    val additionalActionBackgroundColor: Color,
+    val additionalActionContentColor: Color,
+    val undoActionBackgroundColor: Color,
+    val undoActionContentColor: Color
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null) return false
+        if (this::class != other::class) return false
+
+        other as SwipeToRevealActionColors
+
+        if (actionBackgroundColor != other.actionBackgroundColor) return false
+        if (actionContentColor != other.actionContentColor) return false
+        if (additionalActionBackgroundColor != other.additionalActionBackgroundColor) return false
+        if (additionalActionContentColor != other.additionalActionContentColor) return false
+        if (undoActionBackgroundColor != other.undoActionBackgroundColor) return false
+        if (undoActionContentColor != other.undoActionContentColor) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = actionBackgroundColor.hashCode()
+        result = 31 * result + actionContentColor.hashCode()
+        result = 31 * result + additionalActionBackgroundColor.hashCode()
+        result = 31 * result + additionalActionContentColor.hashCode()
+        result = 31 * result + undoActionBackgroundColor.hashCode()
+        result = 31 * result + undoActionContentColor.hashCode()
+        return result
+    }
+}
+
+/**
+ * A class containing the details required for describing the content of an action composable.
+ *
+ * @param icon A slot for providing the icon for this [SwipeToReveal] action
+ * @param label A slot for providing a text label for this [SwipeToRevealAction] action. The
+ * content provided here will be used in different perspective based on the action type
+ * (action, additional action or undo action).
+ * @param modifier The [Modifier] to be applied on the action.
+ * @param interactionSource The [MutableInteractionSource] representing the stream of
+ * interactions with this action.
+ * @param onClick Called when the user clicks the action.
+ */
+@ExperimentalWearMaterialApi
+public class SwipeToRevealAction constructor(
+    val icon: (@Composable () -> Unit)?,
+    val label: (@Composable () -> Unit)?,
+    val modifier: Modifier,
+    val interactionSource: MutableInteractionSource,
+    val onClick: () -> Unit
+) {
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (other == null) return false
+        if (this::class != other::class) return false
+
+        other as SwipeToRevealAction
+
+        if (icon != other.icon) return false
+        if (label != other.label) return false
+        if (modifier != other.modifier) return false
+        if (interactionSource != other.interactionSource) return false
+        if (onClick != other.onClick) return false
+
+        return true
+    }
+
+    override fun hashCode(): Int {
+        var result = icon.hashCode()
+        result = 31 * result + label.hashCode()
+        result = 31 * result + modifier.hashCode()
+        result = 31 * result + interactionSource.hashCode()
+        result = 31 * result + onClick.hashCode()
+        return result
+    }
+}
+
+@OptIn(ExperimentalWearMaterialApi::class, ExperimentalWearFoundationApi::class)
+@Composable
+private fun SwipeToRevealComponent(
+    action: SwipeToRevealAction,
+    revealState: RevealState,
+    modifier: Modifier,
+    additionalAction: SwipeToRevealAction?,
+    undoAction: SwipeToRevealAction?,
+    colors: SwipeToRevealActionColors,
+    shape: Shape,
+    content: @Composable () -> Unit
+) {
+    val coroutineScope = rememberCoroutineScope()
+    SwipeToReveal(
+        state = revealState,
+        modifier = modifier,
+        onFullSwipe = action.onClick,
+        action = {
+            SwipeToRevealAction(
+                revealState = revealState,
+                coroutineScope = coroutineScope,
+                action = action,
+                backgroundColor = colors.actionBackgroundColor,
+                contentColor = colors.actionContentColor,
+                shape = shape,
+                animateTo = RevealValue.Revealed
+            )
+        },
+        additionalAction =
+        additionalAction?.let {
+            {
+                SwipeToRevealAction(
+                    revealState = revealState,
+                    coroutineScope = coroutineScope,
+                    action = additionalAction,
+                    backgroundColor = colors.additionalActionBackgroundColor,
+                    contentColor = colors.additionalActionContentColor,
+                    shape = shape,
+                    animateTo = RevealValue.Revealed
+                )
+            }
+        },
+        undoAction =
+        undoAction?.label?.let {
+            {
+                Box(
+                    modifier = undoAction.modifier
+                        .clickable(
+                            interactionSource = undoAction.interactionSource,
+                            indication = rememberRipple(),
+                            role = Role.Button,
+                            onClick = {
+                                coroutineScope.launch { revealState.animateTo(RevealValue.Covered) }
+                                undoAction.onClick()
+                            }
+                        )
+                        .clip(CircleShape)
+                        .background(color = colors.undoActionBackgroundColor)
+                        .padding(
+                            horizontal = SwipeToRevealDefaults.UndoButtonHorizontalPadding,
+                            vertical = SwipeToRevealDefaults.UndoButtonVerticalPadding
+                        ),
+                    contentAlignment = Alignment.Center
+                ) {
+                    CompositionLocalProvider(
+                        LocalContentColor provides colors.undoActionContentColor
+                    ) {
+                        undoAction.label.invoke()
+                    }
+                }
+            }
+        },
+        content = content
+    )
+}
+
+/**
+ * Action composables for [SwipeToReveal].
+ */
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
+@Composable
+private fun RevealScope.SwipeToRevealAction(
+    revealState: RevealState,
+    coroutineScope: CoroutineScope,
+    action: SwipeToRevealAction,
+    backgroundColor: Color,
+    contentColor: Color,
+    shape: Shape,
+    animateTo: RevealValue
+) {
+    // Change opacity of shape from 0% to 100% between 10% and 20% of the progress
+    val shapeAlpha =
+        if (revealOffset > 0)
+            ((-revealState.offset - revealOffset * 0.1f) / (0.1f * revealOffset))
+                .coerceIn(0.0f, 1.0f)
+        else 1f
+    Row(
+        modifier = action.modifier
+            .graphicsLayer { alpha = shapeAlpha }
+            .background(backgroundColor, shape)
+            // Limit the incoming constraints to max height
+            .heightIn(min = 0.dp, max = SwipeToRevealDefaults.ActionMaxHeight)
+            // Then, fill the max height based on incoming constraints
+            .fillMaxSize()
+            .clickable(
+                interactionSource = action.interactionSource,
+                indication = rememberRipple(),
+                role = Role.Button,
+                onClick = {
+                    coroutineScope.launch { revealState.animateTo(animateTo) }
+                    action.onClick()
+                }
+            ),
+        horizontalArrangement = Arrangement.Center,
+        verticalAlignment = Alignment.CenterVertically
+    ) {
+        CompositionLocalProvider(
+            LocalContentColor provides contentColor
+        ) {
+            if (action.icon != null) {
+                ActionIcon(
+                    revealState = revealState,
+                    content = action.icon
+                )
+            }
+            if (abs(revealState.offset) > revealOffset && action.label != null) {
+                Spacer(Modifier.size(5.dp))
+                action.label.invoke()
+            }
+        }
+    }
+}
+
+@OptIn(ExperimentalWearFoundationApi::class)
+@Composable
+private fun RevealScope.ActionIcon(
+    revealState: RevealState,
+    content: @Composable () -> Unit
+) {
+    // Change opacity of icons from 0% to 100% between 50% to 75% of the progress
+    val iconAlpha =
+        if (revealOffset > 0)
+            ((-revealState.offset - revealOffset * 0.5f) / (revealOffset * 0.25f))
+                .coerceIn(0.0f, 1.0f)
+        else 1f
+    // Scale icons from 50% to 100% between 50% and 100% of the progress
+    val iconScale =
+        if (revealOffset > 0)
+            ((-revealState.offset - revealOffset * 0.5f) / revealOffset)
+                .coerceIn(0.0f, 0.5f) + 0.5f
+        else 1f
+    Box(
+        modifier = Modifier.graphicsLayer {
+            alpha = iconAlpha
+            scaleX = iconScale
+            scaleY = iconScale
+        }
+    ) {
+        content()
+    }
+}
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Swipeable.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Swipeable.kt
index 9a6fda0..b605836 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Swipeable.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Swipeable.kt
@@ -16,6 +16,7 @@
 
 package androidx.wear.compose.material
 
+import androidx.annotation.FloatRange
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.SpringSpec
@@ -442,7 +443,7 @@
 class SwipeProgress<T>(
     val from: T,
     val to: T,
-    /*@FloatRange(from = 0.0, to = 1.0)*/
+    @FloatRange(from = 0.0, to = 1.0)
     val fraction: Float
 ) {
     override fun equals(other: Any?): Boolean {
@@ -660,7 +661,7 @@
 @Immutable
 @ExperimentalWearMaterialApi
 data class FractionalThreshold(
-    /*@FloatRange(from = 0.0, to = 1.0)*/
+    @FloatRange(from = 0.0, to = 1.0)
     private val fraction: Float
 ) : ThresholdConfig {
     override fun Density.computeThreshold(fromValue: Float, toValue: Float): Float {
@@ -693,11 +694,11 @@
 @Immutable
 @ExperimentalWearMaterialApi
 class ResistanceConfig(
-    /*@FloatRange(from = 0.0, fromInclusive = false)*/
+    @FloatRange(from = 0.0, fromInclusive = false)
     val basis: Float,
-    /*@FloatRange(from = 0.0)*/
+    @FloatRange(from = 0.0)
     val factorAtMin: Float = StandardResistanceFactor,
-    /*@FloatRange(from = 0.0)*/
+    @FloatRange(from = 0.0)
     val factorAtMax: Float = StandardResistanceFactor
 ) {
     fun computeResistance(overflow: Float): Float {
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonScreenshotTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonScreenshotTest.kt
new file mode 100644
index 0000000..3903cba
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonScreenshotTest.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.wear.compose.material3
+
+import android.os.Build
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Star
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class IconToggleButtonScreenshotTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    @Test
+    fun iconToggleButtonEnabledAndChecked() = rule.verifyScreenshot(
+        methodName = testName.methodName,
+        screenshotRule = screenshotRule,
+        content = { sampleIconToggleButton() }
+    )
+
+    @Test
+    fun iconToggleButtonEnabledAndUnchecked() = rule.verifyScreenshot(
+        methodName = testName.methodName,
+        screenshotRule = screenshotRule,
+        content = { sampleIconToggleButton(checked = false) }
+    )
+
+    @Test
+    fun iconToggleButtonDisabledAndChecked() = rule.verifyScreenshot(
+        methodName = testName.methodName,
+        screenshotRule = screenshotRule,
+        content = { sampleIconToggleButton(enabled = false) }
+    )
+
+    @Test
+    fun iconToggleButtonDisabledAndUnchecked() = rule.verifyScreenshot(
+        methodName = testName.methodName,
+        screenshotRule = screenshotRule,
+        content = { sampleIconToggleButton(enabled = false, checked = false) }
+    )
+
+    @Composable
+    private fun sampleIconToggleButton(
+        enabled: Boolean = true,
+        checked: Boolean = true
+    ) {
+        IconToggleButton(
+            checked = checked,
+            onCheckedChange = {},
+            enabled = enabled,
+            modifier = Modifier.testTag(TEST_TAG)
+        ) {
+            Icon(
+                imageVector = Icons.Outlined.Star,
+                contentDescription = "Favourite"
+            )
+        }
+    }
+}
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
index afa5a80..093455c 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
@@ -30,6 +30,7 @@
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.Add
 import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertAgainstGolden
 import androidx.compose.testutils.assertContainsColor
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -53,6 +54,7 @@
 import androidx.compose.ui.unit.height
 import androidx.compose.ui.unit.isUnspecified
 import androidx.compose.ui.unit.toSize
+import androidx.test.screenshot.AndroidXScreenshotTestRule
 import kotlin.math.abs
 import org.junit.Assert
 
@@ -279,6 +281,27 @@
     }
 }
 
+@RequiresApi(Build.VERSION_CODES.O)
+internal fun ComposeContentTestRule.verifyScreenshot(
+    methodName: String,
+    screenshotRule: AndroidXScreenshotTestRule,
+    testTag: String = TEST_TAG,
+    content: @Composable () -> Unit
+) {
+    setContentWithTheme {
+        Box(
+            modifier = Modifier
+                .fillMaxSize()
+                .background(MaterialTheme.colorScheme.background)
+        ) {
+            content()
+        }
+    }
+
+    onNodeWithTag(testTag).captureToImage()
+        .assertAgainstGolden(screenshotRule, methodName)
+}
+
 private fun ImageBitmap.histogram(): MutableMap<Color, Long> {
     val pixels = this.toPixelMap()
     val histogram = mutableMapOf<Color, Long>()
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonScreenshotTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonScreenshotTest.kt
new file mode 100644
index 0000000..71a30a6
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonScreenshotTest.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.wear.compose.material3
+
+import android.os.Build
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class TextToggleButtonScreenshotTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @get:Rule
+    val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+    @get:Rule
+    val testName = TestName()
+
+    @Test
+    fun textToggleButtonEnabledAndChecked() = rule.verifyScreenshot(
+        methodName = testName.methodName,
+        screenshotRule = screenshotRule,
+        content = { sampleTextToggleButton() }
+    )
+
+    @Test
+    fun textToggleButtonEnabledAndUnchecked() = rule.verifyScreenshot(
+        methodName = testName.methodName,
+        screenshotRule = screenshotRule,
+        content = { sampleTextToggleButton(checked = false) }
+    )
+
+    @Test
+    fun textToggleButtonDisabledAndChecked() = rule.verifyScreenshot(
+        methodName = testName.methodName,
+        screenshotRule = screenshotRule,
+        content = { sampleTextToggleButton(enabled = false) }
+    )
+
+    @Test
+    fun textToggleButtonDisabledAndUnchecked() = rule.verifyScreenshot(
+        methodName = testName.methodName,
+        screenshotRule = screenshotRule,
+        content = { sampleTextToggleButton(enabled = false, checked = false) }
+    )
+
+    @Composable
+    private fun sampleTextToggleButton(
+        enabled: Boolean = true,
+        checked: Boolean = true
+    ) {
+        TextToggleButton(
+            checked = checked,
+            onCheckedChange = {},
+            enabled = enabled,
+            modifier = Modifier.testTag(TEST_TAG)) {
+            Text(text = if (checked) "ON" else "OFF")
+        }
+    }
+}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ContentAlpha.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ContentAlpha.kt
index b978a2b..a66faf1 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ContentAlpha.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ContentAlpha.kt
@@ -15,6 +15,7 @@
  */
 package androidx.wear.compose.material3
 
+import androidx.annotation.FloatRange
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ProvidableCompositionLocal
 import androidx.compose.runtime.compositionLocalOf
@@ -83,9 +84,9 @@
      */
     @Composable
     private fun contentAlpha(
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         highContrastAlpha: Float,
-        /*@FloatRange(from = 0.0, to = 1.0)*/
+        @FloatRange(from = 0.0, to = 1.0)
         lowContrastAlpha: Float
     ): Float {
         val contentColor = LocalContentColor.current
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Typography.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Typography.kt
index 8c3aaa1..341fc8d 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Typography.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Typography.kt
@@ -15,13 +15,15 @@
  */
 package androidx.wear.compose.material3
 
+import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.runtime.staticCompositionLocalOf
 import androidx.compose.ui.text.PlatformTextStyle
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.sp
+import androidx.wear.compose.material3.tokens.TypographyKeyTokens
+import androidx.wear.compose.material3.tokens.TypographyTokens
 
 /**
  * Class holding typography definitions as defined by the Wear Material typography specification.
@@ -95,84 +97,19 @@
 ) {
     public constructor (
         defaultFontFamily: FontFamily = FontFamily.Default,
-        displayLarge: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Normal,
-            fontSize = 40.sp,
-            lineHeight = 44.sp,
-            letterSpacing = 0.sp
-        ),
-        displayMedium: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Normal,
-            fontSize = 30.sp,
-            lineHeight = 34.sp,
-            letterSpacing = 0.sp
-        ),
-        displaySmall: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Medium,
-            fontSize = 24.sp,
-            lineHeight = 28.sp,
-            letterSpacing = 0.sp,
-        ),
-        titleLarge: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Medium,
-            fontSize = 20.sp,
-            lineHeight = 22.sp,
-            letterSpacing = 0.2.sp
-        ),
-        titleMedium: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Medium,
-            fontSize = 16.sp,
-            lineHeight = 18.sp,
-            letterSpacing = 0.3.sp
-        ),
-        titleSmall: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Medium,
-            fontSize = 14.sp,
-            lineHeight = 16.sp,
-            letterSpacing = 0.3.sp
-        ),
-        labelLarge: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Medium,
-            fontSize = 20.sp,
-            lineHeight = 22.sp,
-            letterSpacing = 0.2.sp
-        ),
-        labelMedium: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Medium,
-            fontSize = 15.sp,
-            lineHeight = 16.sp,
-            letterSpacing = 0.2.sp
-        ),
-        labelSmall: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Medium,
-            fontSize = 13.sp,
-            lineHeight = 14.sp,
-            letterSpacing = 0.3.sp
-        ),
-        bodyLarge: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Normal,
-            fontSize = 16.sp,
-            lineHeight = 18.sp,
-            letterSpacing = 0.3.sp,
-        ),
-        bodyMedium: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Normal,
-            fontSize = 14.sp,
-            lineHeight = 18.sp,
-            letterSpacing = 0.2.sp
-        ),
-        bodySmall: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Medium,
-            fontSize = 12.sp,
-            lineHeight = 16.sp,
-            letterSpacing = 0.4.sp
-        ),
-        bodyExtraSmall: TextStyle = DefaultTextStyle.copy(
-            fontWeight = FontWeight.Normal,
-            fontSize = 11.sp,
-            lineHeight = 14.sp,
-            letterSpacing = 0.4.sp
-        )
+        displayLarge: TextStyle = TypographyTokens.DisplayLarge,
+        displayMedium: TextStyle = TypographyTokens.DisplayMedium,
+        displaySmall: TextStyle = TypographyTokens.DisplaySmall,
+        titleLarge: TextStyle = TypographyTokens.TitleLarge,
+        titleMedium: TextStyle = TypographyTokens.TitleMedium,
+        titleSmall: TextStyle = TypographyTokens.TitleSmall,
+        labelLarge: TextStyle = TypographyTokens.LabelLarge,
+        labelMedium: TextStyle = TypographyTokens.LabelMedium,
+        labelSmall: TextStyle = TypographyTokens.LabelSmall,
+        bodyLarge: TextStyle = TypographyTokens.BodyLarge,
+        bodyMedium: TextStyle = TypographyTokens.BodyMedium,
+        bodySmall: TextStyle = TypographyTokens.BodySmall,
+        bodyExtraSmall: TextStyle = TypographyTokens.BodyExtraSmall
     ) : this(
         displayLarge = displayLarge.withDefaultFontFamily(defaultFontFamily),
         displayMedium = displayMedium.withDefaultFontFamily(defaultFontFamily),
@@ -289,6 +226,36 @@
 )
 
 /**
+ * Helper function for typography tokens.
+ */
+internal fun Typography.fromToken(value: TypographyKeyTokens): TextStyle {
+    return when (value) {
+        TypographyKeyTokens.DisplayLarge -> displayLarge
+        TypographyKeyTokens.DisplayMedium -> displayMedium
+        TypographyKeyTokens.DisplaySmall -> displaySmall
+        TypographyKeyTokens.TitleLarge -> titleLarge
+        TypographyKeyTokens.TitleMedium -> titleMedium
+        TypographyKeyTokens.TitleSmall -> titleSmall
+        TypographyKeyTokens.LabelLarge -> labelLarge
+        TypographyKeyTokens.LabelMedium -> labelMedium
+        TypographyKeyTokens.LabelSmall -> labelSmall
+        TypographyKeyTokens.BodyLarge -> bodyLarge
+        TypographyKeyTokens.BodyMedium -> bodyMedium
+        TypographyKeyTokens.BodySmall -> bodySmall
+        TypographyKeyTokens.BodyExtraSmall -> bodyExtraSmall
+    }
+}
+
+/**
+ * Helper function to convert [TypographyKeyTokens] to [TextStyle].
+ */
+@Composable
+@ReadOnlyComposable
+internal fun TypographyKeyTokens.toTextStyle(): TextStyle {
+    return MaterialTheme.typography.fromToken(this)
+}
+
+/**
  * This Ambient holds on to the current definition of typography for this application as described
  * by the Wear Material spec. You can read the values in it when creating custom components that
  * want to use Wear Material types, as well as override the values when you want to re-style a part
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt
new file mode 100644
index 0000000..2eea3e2
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+// VERSION: v0_8
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.wear.compose.material3.tokens
+
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+
+internal object TypefaceTokens {
+    val Brand = FontFamily.SansSerif
+    val MediumWeight = FontWeight.Medium
+    val Plain = FontFamily.SansSerif
+    val RegularWeight = FontWeight.Normal
+    val WeightBold = FontWeight.Bold
+}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypescaleTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypescaleTokens.kt
new file mode 100644
index 0000000..858bbf7
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypescaleTokens.kt
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+// VERSION: v0_9
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.wear.compose.material3.tokens
+
+import androidx.compose.ui.unit.sp
+
+internal object TypeScaleTokens {
+    val BodyExtraSmallFont = TypefaceTokens.Brand
+    val BodyExtraSmallLineHeight = 14.0.sp
+    val BodyExtraSmallSize = 11.sp
+    val BodyExtraSmallTracking = 0.4.sp
+    val BodyExtraSmallWeight = TypefaceTokens.RegularWeight
+    val BodyExtraSmallWeightProminent = TypefaceTokens.WeightBold
+    val BodyLargeFont = TypefaceTokens.Brand
+    val BodyLargeLineHeight = 18.0.sp
+    val BodyLargeSize = 16.sp
+    val BodyLargeTracking = 0.3.sp
+    val BodyLargeWeight = TypefaceTokens.RegularWeight
+    val BodyLargeWeightProminent = TypefaceTokens.WeightBold
+    val BodyMediumFont = TypefaceTokens.Brand
+    val BodyMediumLineHeight = 18.0.sp
+    val BodyMediumSize = 14.sp
+    val BodyMediumTracking = 0.2.sp
+    val BodyMediumWeight = TypefaceTokens.RegularWeight
+    val BodyMediumWeightProminent = TypefaceTokens.WeightBold
+    val BodySmallFont = TypefaceTokens.Brand
+    val BodySmallLineHeight = 16.0.sp
+    val BodySmallSize = 12.sp
+    val BodySmallTracking = 0.4.sp
+    val BodySmallWeight = TypefaceTokens.MediumWeight
+    val BodySmallWeightProminent = TypefaceTokens.WeightBold
+    val DisplayLargeFont = TypefaceTokens.Brand
+    val DisplayLargeLineHeight = 44.0.sp
+    val DisplayLargeSize = 40.sp
+    val DisplayLargeTracking = 0.0.sp
+    val DisplayLargeWeight = TypefaceTokens.RegularWeight
+    val DisplayMediumFont = TypefaceTokens.Brand
+    val DisplayMediumLineHeight = 34.0.sp
+    val DisplayMediumSize = 30.sp
+    val DisplayMediumTracking = 0.0.sp
+    val DisplayMediumWeight = TypefaceTokens.RegularWeight
+    val DisplaySmallFont = TypefaceTokens.Brand
+    val DisplaySmallLineHeight = 28.0.sp
+    val DisplaySmallSize = 24.sp
+    val DisplaySmallTracking = 0.0.sp
+    val DisplaySmallWeight = TypefaceTokens.MediumWeight
+    val LabelLargeFont = TypefaceTokens.Brand
+    val LabelLargeLineHeight = 22.0.sp
+    val LabelLargeSize = 20.sp
+    val LabelLargeTracking = 0.2.sp
+    val LabelLargeWeight = TypefaceTokens.MediumWeight
+    val LabelMediumFont = TypefaceTokens.Brand
+    val LabelMediumLineHeight = 16.0.sp
+    val LabelMediumSize = 15.sp
+    val LabelMediumTracking = 0.2.sp
+    val LabelMediumWeight = TypefaceTokens.MediumWeight
+    val LabelSmallFont = TypefaceTokens.Brand
+    val LabelSmallLineHeight = 14.0.sp
+    val LabelSmallSize = 13.sp
+    val LabelSmallTracking = 0.3.sp
+    val LabelSmallWeight = TypefaceTokens.MediumWeight
+    val TitleLargeFont = TypefaceTokens.Brand
+    val TitleLargeLineHeight = 22.0.sp
+    val TitleLargeSize = 20.sp
+    val TitleLargeTracking = 0.2.sp
+    val TitleLargeWeight = TypefaceTokens.MediumWeight
+    val TitleMediumFont = TypefaceTokens.Brand
+    val TitleMediumLineHeight = 18.0.sp
+    val TitleMediumSize = 16.sp
+    val TitleMediumTracking = 0.3.sp
+    val TitleMediumWeight = TypefaceTokens.MediumWeight
+    val TitleSmallFont = TypefaceTokens.Brand
+    val TitleSmallLineHeight = 16.0.sp
+    val TitleSmallSize = 14.sp
+    val TitleSmallTracking = 0.3.sp
+    val TitleSmallWeight = TypefaceTokens.MediumWeight
+}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt
new file mode 100644
index 0000000..40869af
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+// VERSION: v0_8
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.wear.compose.material3.tokens
+
+internal enum class TypographyKeyTokens {
+    BodyExtraSmall,
+    BodyLarge,
+    BodyMedium,
+    BodySmall,
+    DisplayLarge,
+    DisplayMedium,
+    DisplaySmall,
+    LabelLarge,
+    LabelMedium,
+    LabelSmall,
+    TitleLarge,
+    TitleMedium,
+    TitleSmall,
+}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt
new file mode 100644
index 0000000..60131a2
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+// VERSION: v0_8
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.wear.compose.material3.tokens
+
+import androidx.wear.compose.material3.DefaultTextStyle
+
+internal object TypographyTokens {
+    val BodyExtraSmall =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.BodyExtraSmallFont,
+            fontWeight = TypeScaleTokens.BodyExtraSmallWeight,
+            fontSize = TypeScaleTokens.BodyExtraSmallSize,
+            lineHeight = TypeScaleTokens.BodyExtraSmallLineHeight,
+            letterSpacing = TypeScaleTokens.BodyExtraSmallTracking,
+        )
+    val BodyLarge =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.BodyLargeFont,
+            fontWeight = TypeScaleTokens.BodyLargeWeight,
+            fontSize = TypeScaleTokens.BodyLargeSize,
+            lineHeight = TypeScaleTokens.BodyLargeLineHeight,
+            letterSpacing = TypeScaleTokens.BodyLargeTracking,
+        )
+    val BodyMedium =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.BodyMediumFont,
+            fontWeight = TypeScaleTokens.BodyMediumWeight,
+            fontSize = TypeScaleTokens.BodyMediumSize,
+            lineHeight = TypeScaleTokens.BodyMediumLineHeight,
+            letterSpacing = TypeScaleTokens.BodyMediumTracking,
+        )
+    val BodySmall =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.BodySmallFont,
+            fontWeight = TypeScaleTokens.BodySmallWeight,
+            fontSize = TypeScaleTokens.BodySmallSize,
+            lineHeight = TypeScaleTokens.BodySmallLineHeight,
+            letterSpacing = TypeScaleTokens.BodySmallTracking,
+        )
+    val DisplayLarge =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.DisplayLargeFont,
+            fontWeight = TypeScaleTokens.DisplayLargeWeight,
+            fontSize = TypeScaleTokens.DisplayLargeSize,
+            lineHeight = TypeScaleTokens.DisplayLargeLineHeight,
+            letterSpacing = TypeScaleTokens.DisplayLargeTracking,
+        )
+    val DisplayMedium =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.DisplayMediumFont,
+            fontWeight = TypeScaleTokens.DisplayMediumWeight,
+            fontSize = TypeScaleTokens.DisplayMediumSize,
+            lineHeight = TypeScaleTokens.DisplayMediumLineHeight,
+            letterSpacing = TypeScaleTokens.DisplayMediumTracking,
+        )
+    val DisplaySmall =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.DisplaySmallFont,
+            fontWeight = TypeScaleTokens.DisplaySmallWeight,
+            fontSize = TypeScaleTokens.DisplaySmallSize,
+            lineHeight = TypeScaleTokens.DisplaySmallLineHeight,
+            letterSpacing = TypeScaleTokens.DisplaySmallTracking,
+        )
+    val LabelLarge =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.LabelLargeFont,
+            fontWeight = TypeScaleTokens.LabelLargeWeight,
+            fontSize = TypeScaleTokens.LabelLargeSize,
+            lineHeight = TypeScaleTokens.LabelLargeLineHeight,
+            letterSpacing = TypeScaleTokens.LabelLargeTracking,
+        )
+    val LabelMedium =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.LabelMediumFont,
+            fontWeight = TypeScaleTokens.LabelMediumWeight,
+            fontSize = TypeScaleTokens.LabelMediumSize,
+            lineHeight = TypeScaleTokens.LabelMediumLineHeight,
+            letterSpacing = TypeScaleTokens.LabelMediumTracking,
+        )
+    val LabelSmall =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.LabelSmallFont,
+            fontWeight = TypeScaleTokens.LabelSmallWeight,
+            fontSize = TypeScaleTokens.LabelSmallSize,
+            lineHeight = TypeScaleTokens.LabelSmallLineHeight,
+            letterSpacing = TypeScaleTokens.LabelSmallTracking,
+        )
+    val TitleLarge =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.TitleLargeFont,
+            fontWeight = TypeScaleTokens.TitleLargeWeight,
+            fontSize = TypeScaleTokens.TitleLargeSize,
+            lineHeight = TypeScaleTokens.TitleLargeLineHeight,
+            letterSpacing = TypeScaleTokens.TitleLargeTracking,
+        )
+    val TitleMedium =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.TitleMediumFont,
+            fontWeight = TypeScaleTokens.TitleMediumWeight,
+            fontSize = TypeScaleTokens.TitleMediumSize,
+            lineHeight = TypeScaleTokens.TitleMediumLineHeight,
+            letterSpacing = TypeScaleTokens.TitleMediumTracking,
+        )
+    val TitleSmall =
+        DefaultTextStyle.copy(
+            fontFamily = TypeScaleTokens.TitleSmallFont,
+            fontWeight = TypeScaleTokens.TitleSmallWeight,
+            fontSize = TypeScaleTokens.TitleSmallSize,
+            lineHeight = TypeScaleTokens.TitleSmallLineHeight,
+            letterSpacing = TypeScaleTokens.TitleSmallTracking,
+        )
+}
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SwipeToRevealDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SwipeToRevealDemo.kt
index 6c5270e..58777cc 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SwipeToRevealDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SwipeToRevealDemo.kt
@@ -16,57 +16,39 @@
 
 package androidx.wear.compose.integration.demos
 
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Email
-import androidx.compose.material.icons.outlined.Delete
-import androidx.compose.material.icons.outlined.MoreVert
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
 import androidx.wear.compose.foundation.ExpandableState
 import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
-import androidx.wear.compose.foundation.RevealScope
-import androidx.wear.compose.foundation.RevealState
 import androidx.wear.compose.foundation.RevealValue
-import androidx.wear.compose.foundation.SwipeToReveal
 import androidx.wear.compose.foundation.createAnchors
 import androidx.wear.compose.foundation.expandableItem
-import androidx.wear.compose.foundation.fractionalPositionalThreshold
 import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
 import androidx.wear.compose.foundation.rememberExpandableState
 import androidx.wear.compose.foundation.rememberRevealState
 import androidx.wear.compose.material.AppCard
 import androidx.wear.compose.material.Chip
 import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.ExperimentalWearMaterialApi
 import androidx.wear.compose.material.Icon
-import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.SwipeToRevealCard
+import androidx.wear.compose.material.SwipeToRevealChip
+import androidx.wear.compose.material.SwipeToRevealDefaults
 import androidx.wear.compose.material.Text
-import kotlin.math.abs
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
 
 @Composable
 fun SwipeToRevealChips() {
@@ -139,12 +121,15 @@
     SwipeToRevealSingleAction()
 }
 
+/**
+ * Swipe to reveal in RTL. This is should be identical to LTR.
+ */
 @Composable
 fun SwipeToRevealInRtl() {
     SwipeToRevealSingleAction(LayoutDirection.Rtl)
 }
 
-@OptIn(ExperimentalWearFoundationApi::class)
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
 @Composable
 private fun SwipeToRevealChipExpandable(
     expandableState: ExpandableState
@@ -156,34 +141,37 @@
             expandableState.expanded = false
         }
     }
-    Box(
-        contentAlignment = Alignment.Center,
-        modifier = Modifier.size(width = 200.dp, height = 52.dp)
+    SwipeToRevealChip(
+        revealState = state,
+        action = SwipeToRevealDefaults.action(
+            icon = { Icon(SwipeToRevealDefaults.Delete, contentDescription = "Delete") },
+            label = { Text(text = "Delete") },
+        ),
+        additionalAction = SwipeToRevealDefaults.additionalAction(
+            icon = { Icon(SwipeToRevealDefaults.MoreOptions, contentDescription = "More Options") },
+        ),
+        undoAction = SwipeToRevealDefaults.undoAction(
+            label = { Text(text = "Undo") },
+        ),
     ) {
-        SwipeToRevealWithDefaultButtons(
-            shape = CircleShape,
-            state = state,
-        ) {
-            Chip(
-                onClick = { /*TODO*/ },
-                colors = ChipDefaults.secondaryChipColors(),
-                modifier = Modifier.fillMaxWidth(),
-                label = {
-                    Text("S2R Chip with defaults")
-                }
-            )
-        }
+        Chip(
+            onClick = { /*TODO*/ },
+            colors = ChipDefaults.secondaryChipColors(),
+            modifier = Modifier.fillMaxWidth(),
+            label = {
+                Text("S2R Chip with defaults")
+            }
+        )
     }
 }
 
-@OptIn(ExperimentalWearFoundationApi::class)
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
 @Composable
 private fun SwipeToRevealCardExpandable(
     expandableState: ExpandableState,
     from: String,
     email: String
 ) {
-
     val state = rememberRevealState()
     LaunchedEffect(state.currentValue) {
         if (state.currentValue == RevealValue.Revealed) {
@@ -191,13 +179,22 @@
             expandableState.expanded = false
         }
     }
-    SwipeToRevealWithDefaultButtons(
-        shape = RoundedCornerShape(30.dp),
-        state = state
+    SwipeToRevealCard(
+        revealState = state,
+        action = SwipeToRevealDefaults.action(
+            icon = { Icon(SwipeToRevealDefaults.Delete, contentDescription = "Delete") },
+            label = { Text(text = "Delete") },
+        ),
+        additionalAction = SwipeToRevealDefaults.additionalAction(
+            icon = { Icon(SwipeToRevealDefaults.MoreOptions, contentDescription = "More Options") },
+        ),
+        undoAction = SwipeToRevealDefaults.undoAction(
+            label = { Text(text = "Undo") },
+        ),
     ) {
         AppCard(
             onClick = {},
-            modifier = Modifier.size(width = 200.dp, height = 100.dp),
+            modifier = Modifier.width(width = 200.dp),
             appName = { Text("Gmail") },
             appImage = {
                 Icon(
@@ -206,7 +203,7 @@
                 )
             },
             time = { Text("now") },
-            title = { Text("From: $from") }
+            title = { Text("From: $from", maxLines = 1, overflow = TextOverflow.Ellipsis) }
         ) {
             Text(
                 text = email,
@@ -217,52 +214,7 @@
     }
 }
 
-@OptIn(ExperimentalWearFoundationApi::class)
-@Composable
-private fun SwipeToRevealWithDefaultButtons(
-    state: RevealState = rememberRevealState(),
-    shape: Shape = CircleShape,
-    content: @Composable () -> Unit
-) {
-    val coroutineScope = rememberCoroutineScope()
-    SwipeToReveal(
-        action = {
-            SwipeToRevealAction(
-                color = MaterialTheme.colors.error,
-                icon = Icons.Outlined.Delete,
-                text = "Clear",
-                contentDescription = "Delete",
-                onClick = { state.animateTo(RevealValue.Revealed) },
-                shape = shape,
-                coroutineScope = coroutineScope,
-                state = state
-            )
-        },
-        additionalAction = {
-            SwipeToRevealAction(
-                color = MaterialTheme.colors.onSurfaceVariant,
-                icon = Icons.Outlined.MoreVert,
-                onClick = { state.animateTo(RevealValue.Covered) },
-                shape = shape,
-                coroutineScope = coroutineScope,
-                state = state
-            )
-        },
-        undoAction = {
-            Chip(
-                modifier = Modifier.fillMaxWidth(),
-                onClick = { coroutineScope.launch { state.animateTo(RevealValue.Covered) } },
-                colors = ChipDefaults.secondaryChipColors(),
-                border = ChipDefaults.outlinedChipBorder(),
-                label = { Text(text = "Undo") }
-            )
-        },
-        state = state,
-        content = content,
-    )
-}
-
-@OptIn(ExperimentalWearFoundationApi::class)
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
 @Composable
 private fun SwipeToRevealSingleAction(
     layoutDirection: LayoutDirection = LayoutDirection.Ltr
@@ -281,26 +233,24 @@
                 state = expandableState[curr]
             ) { expanded ->
                 val state = rememberRevealState(
-                    anchors = createAnchors(revealingAnchor = 0.5f),
-                    positionalThreshold = fractionalPositionalThreshold(0.5f)
+                    // Setting anchor to 0.4 since there is only one action.
+                    anchors = createAnchors(revealingAnchor = 0.4f),
                 )
                 if (expanded) {
                     CompositionLocalProvider(
                         LocalLayoutDirection provides layoutDirection
                     ) {
-                        SwipeToReveal(
-                            action = {
-                                SwipeToRevealAction(
-                                    color = MaterialTheme.colors.error,
-                                    icon = Icons.Outlined.Delete,
-                                    text = "Clear",
-                                    contentDescription = "Delete",
-                                    onClick = { state.animateTo(RevealValue.Revealed) },
-                                    shape = CircleShape,
-                                    state = state
-                                )
-                            },
-                            state = state
+                        SwipeToRevealChip(
+                            revealState = state,
+                            action = SwipeToRevealDefaults.action(
+                                icon = {
+                                    Icon(
+                                        SwipeToRevealDefaults.Delete,
+                                        contentDescription = "Delete"
+                                    )
+                                },
+                                label = { Text(text = "Delete") },
+                            ),
                         ) {
                             Chip(
                                 onClick = { /*TODO*/ },
@@ -323,33 +273,3 @@
         }
     }
 }
-
-@OptIn(ExperimentalWearFoundationApi::class)
-@Composable
-private fun RevealScope.SwipeToRevealAction(
-    color: Color,
-    icon: ImageVector,
-    text: String? = null,
-    contentDescription: String? = null,
-    onClick: suspend () -> Unit = {},
-    shape: Shape = RoundedCornerShape(15.dp),
-    state: RevealState = rememberRevealState(),
-    coroutineScope: CoroutineScope = rememberCoroutineScope(),
-) {
-    Row(
-        modifier = Modifier
-            .clickable {
-                coroutineScope.launch { onClick() }
-            }
-            .background(color, shape)
-            .fillMaxSize(),
-        horizontalArrangement = Arrangement.Center,
-        verticalAlignment = Alignment.CenterVertically
-    ) {
-        Icon(imageVector = icon, contentDescription = contentDescription, tint = Color.DarkGray)
-        if (abs(state.offset) > revealOffset && text != null) {
-            Spacer(Modifier.size(5.dp))
-            Text(text = text)
-        }
-    }
-}
diff --git a/wear/protolayout/protolayout-renderer/build.gradle b/wear/protolayout/protolayout-renderer/build.gradle
index a29d50f..b483e2a 100644
--- a/wear/protolayout/protolayout-renderer/build.gradle
+++ b/wear/protolayout/protolayout-renderer/build.gradle
@@ -33,7 +33,7 @@
     api(project(":wear:protolayout:protolayout-expression-pipeline"))
     implementation "androidx.concurrent:concurrent-futures:1.1.0"
     implementation("androidx.core:core:1.7.0")
-    implementation("androidx.wear:wear:1.3.0-rc01")
+    implementation("androidx.wear:wear:1.3.0")
 
     testImplementation(libs.mockitoCore4)
     testImplementation(libs.testExtJunit)
diff --git a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/manager/UpdateSchedulerTest.java b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/manager/UpdateSchedulerTest.java
index c96a0bc..b9696c8 100644
--- a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/manager/UpdateSchedulerTest.java
+++ b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/manager/UpdateSchedulerTest.java
@@ -292,6 +292,7 @@
         expect.that(mFired).isEmpty();
     }
 
+    @SuppressWarnings("deprecation") // ScheduledAlarm usage, see b/284981234
     private void advanceToTime(Long targetTime) {
         while (mShadowAlarmManager.peekNextScheduledAlarm() != null
                 && mShadowAlarmManager.peekNextScheduledAlarm().triggerAtTime <= targetTime) {
diff --git a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineManagerTest.java b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineManagerTest.java
index cd97c3c..ba44a1f 100644
--- a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineManagerTest.java
+++ b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineManagerTest.java
@@ -365,6 +365,7 @@
                 .build();
     }
 
+    @SuppressWarnings("deprecation") // ScheduledAlarm usage, see b/284981234
     private void seekToTime(long timeMillis) {
         ShadowAlarmManager shadowAlarmManager = shadowOf(mAlarmManager);
 
diff --git a/wear/watchface/watchface-complications-data-source-samples/build.gradle b/wear/watchface/watchface-complications-data-source-samples/build.gradle
index 5bc5294..bccb6ae 100644
--- a/wear/watchface/watchface-complications-data-source-samples/build.gradle
+++ b/wear/watchface/watchface-complications-data-source-samples/build.gradle
@@ -17,6 +17,7 @@
 plugins {
     id("AndroidXPlugin")
     id("com.android.application")
+    id("kotlin-android")
 }
 
 dependencies {