Merge changes Iea4f404c,Icffdf98b into androidx-main

* changes:
  @samples removing frameworks/support/ prefix
  Removing unused frameworks/support/samples symlink
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/stub/StubCreators.java b/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/stub/StubCreators.java
index 6591e3a..97887bf 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/stub/StubCreators.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/safeparcel/stub/StubCreators.java
@@ -82,4 +82,8 @@
     /** Stub creator for {@link androidx.appsearch.app.VisibilityDocument}. */
     public static class VisibilityDocumentCreator extends AbstractCreator {
     }
+
+    /** Stub creator for {@link androidx.appsearch.stats.SchemaMigrationStats}. */
+    public static class SchemaMigrationStatsCreator extends AbstractCreator {
+    }
 }
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/stats/SchemaMigrationStats.java b/appsearch/appsearch/src/main/java/androidx/appsearch/stats/SchemaMigrationStats.java
index 5c3a226..0a24293 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/stats/SchemaMigrationStats.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/stats/SchemaMigrationStats.java
@@ -16,7 +16,7 @@
 
 package androidx.appsearch.stats;
 
-import android.os.Bundle;
+import android.os.Parcel;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
@@ -24,11 +24,13 @@
 import androidx.appsearch.annotation.CanIgnoreReturnValue;
 import androidx.appsearch.app.AppSearchResult;
 import androidx.appsearch.app.SetSchemaRequest;
-import androidx.appsearch.util.BundleUtil;
-import androidx.core.util.Preconditions;
+import androidx.appsearch.safeparcel.AbstractSafeParcelable;
+import androidx.appsearch.safeparcel.SafeParcelable;
+import androidx.appsearch.safeparcel.stub.StubCreators.SchemaMigrationStatsCreator;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Class holds detailed stats for Schema migration.
@@ -36,7 +38,10 @@
  * @exportToFramework:hide
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public final class SchemaMigrationStats {
[email protected](creator = "SchemaMigrationStatsCreator")
+public final class SchemaMigrationStats extends AbstractSafeParcelable {
+    @NonNull public static final SchemaMigrationStatsCreator CREATOR =
+            new SchemaMigrationStatsCreator();
 
     // Indicate the how a SetSchema call relative to SchemaMigration case.
     @IntDef(
@@ -55,82 +60,114 @@
     /**  This is the second SetSchema call in Migration cases to apply new schema changes */
     public static final int SECOND_CALL_APPLY_NEW_SCHEMA = 2;
 
-    private static final String PACKAGE_NAME_FIELD = "packageName";
-    private static final String DATABASE_FIELD = "database";
-    private static final String STATUS_CODE_FIELD = "StatusCode";
-    private static final String EXECUTOR_ACQUISITION_MILLIS_FIELD =
-            "ExecutorAcquisitionLatencyMillis";
-    private static final String TOTAL_LATENCY_MILLIS_FIELD = "totalLatencyMillis";
-    private static final String GET_SCHEMA_LATENCY_MILLIS_FIELD = "getSchemaLatencyMillis";
-    private static final String QUERY_AND_TRANSFORM_LATENCY_MILLIS_FIELD =
-            "queryAndTransformLatencyMillis";
-    private static final String FIRST_SET_SCHEMA_LATENCY_MILLIS_FIELD =
-            "firstSetSchemaLatencyMillis";
-    private static final String IS_FIRST_SET_SCHEMA_SUCCESS_FIELD = "isFirstSetSchemaSuccess";
-    private static final String SECOND_SET_SCHEMA_LATENCY_MILLIS_FIELD =
-            "secondSetSchemaLatencyMillis";
-    private static final String SAVE_DOCUMENT_LATENCY_MILLIS_FIELD = "saveDocumentLatencyMillis";
-    private static final String TOTAL_NEED_MIGRATED_DOCUMENT_COUNT_FIELD =
-            "totalNeedMigratedDocumentCount";
-    private static final String MIGRATION_FAILURE_COUNT_FIELD = "migrationFailureCount";
-    private static final String TOTAL_SUCCESS_MIGRATED_DOCUMENT_COUNT_FIELD =
-            "totalSuccessMigratedDocumentCount";
-
-    /**
-     * Contains all {@link SchemaMigrationStats} information in a packaged format.
-     *
-     * <p>Keys are the {@code *_FIELD} constants in this class.
-     */
+    @Field(id = 1, getter = "getPackageName")
     @NonNull
-    final Bundle mBundle;
+    private final String mPackageName;
 
-    /** Build a {@link SchemaMigrationStats} from the given bundle. */
-    public SchemaMigrationStats(@NonNull Bundle bundle) {
-        mBundle = Preconditions.checkNotNull(bundle);
-    }
-
-    /**
-     * Returns the {@link Bundle} populated by this builder.
-     *
-     * @exportToFramework:hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @Field(id = 2, getter = "getDatabase")
     @NonNull
-    public Bundle getBundle() {
-        return mBundle;
+    private final String mDatabase;
+
+    @Field(id = 3, getter = "getStatusCode")
+    private final int mStatusCode;
+
+    @Field(id = 4, getter = "getExecutorAcquisitionLatencyMillis")
+    private final int mExecutorAcquisitionLatencyMillis;
+
+    @Field(id = 5, getter = "getTotalLatencyMillis")
+    private final int mTotalLatencyMillis;
+
+    @Field(id = 6, getter = "getGetSchemaLatencyMillis")
+    private final int mGetSchemaLatencyMillis;
+
+    @Field(id = 7, getter = "getQueryAndTransformLatencyMillis")
+    private final int mQueryAndTransformLatencyMillis;
+
+    @Field(id = 8, getter = "getFirstSetSchemaLatencyMillis")
+    private final int mFirstSetSchemaLatencyMillis;
+
+    @Field(id = 9, getter = "isFirstSetSchemaSuccess")
+    private final boolean mIsFirstSetSchemaSuccess;
+
+    @Field(id = 10, getter = "getSecondSetSchemaLatencyMillis")
+    private final int mSecondSetSchemaLatencyMillis;
+
+    @Field(id = 11, getter = "getSaveDocumentLatencyMillis")
+    private final int mSaveDocumentLatencyMillis;
+
+    @Field(id = 12, getter = "getTotalNeedMigratedDocumentCount")
+    private final int mTotalNeedMigratedDocumentCount;
+
+    @Field(id = 13, getter = "getMigrationFailureCount")
+    private final int mMigrationFailureCount;
+
+    @Field(id = 14, getter = "getTotalSuccessMigratedDocumentCount")
+    private final int mTotalSuccessMigratedDocumentCount;
+
+    /** Build a {@link SchemaMigrationStats} from the given parameters. */
+    @Constructor
+    public SchemaMigrationStats(
+            @Param(id = 1) @NonNull String packageName,
+            @Param(id = 2) @NonNull String database,
+            @Param(id = 3) int statusCode,
+            @Param(id = 4) int executorAcquisitionLatencyMillis,
+            @Param(id = 5) int totalLatencyMillis,
+            @Param(id = 6) int getSchemaLatencyMillis,
+            @Param(id = 7) int queryAndTransformLatencyMillis,
+            @Param(id = 8) int firstSetSchemaLatencyMillis,
+            @Param(id = 9) boolean isFirstSetSchemaSuccess,
+            @Param(id = 10) int secondSetSchemaLatencyMillis,
+            @Param(id = 11) int saveDocumentLatencyMillis,
+            @Param(id = 12) int totalNeedMigratedDocumentCount,
+            @Param(id = 13) int migrationFailureCount,
+            @Param(id = 14) int totalSuccessMigratedDocumentCount) {
+        mPackageName = packageName;
+        mDatabase = database;
+        mStatusCode = statusCode;
+        mExecutorAcquisitionLatencyMillis = executorAcquisitionLatencyMillis;
+        mTotalLatencyMillis = totalLatencyMillis;
+        mGetSchemaLatencyMillis = getSchemaLatencyMillis;
+        mQueryAndTransformLatencyMillis = queryAndTransformLatencyMillis;
+        mFirstSetSchemaLatencyMillis = firstSetSchemaLatencyMillis;
+        mIsFirstSetSchemaSuccess = isFirstSetSchemaSuccess;
+        mSecondSetSchemaLatencyMillis = secondSetSchemaLatencyMillis;
+        mSaveDocumentLatencyMillis = saveDocumentLatencyMillis;
+        mTotalNeedMigratedDocumentCount = totalNeedMigratedDocumentCount;
+        mMigrationFailureCount = migrationFailureCount;
+        mTotalSuccessMigratedDocumentCount = totalSuccessMigratedDocumentCount;
     }
 
     /** Returns calling package name. */
     @NonNull
     public String getPackageName() {
-        return mBundle.getString(PACKAGE_NAME_FIELD);
+        return mPackageName;
     }
 
     /** Returns calling database name. */
     @NonNull
     public String getDatabase() {
-        return mBundle.getString(DATABASE_FIELD);
+        return mDatabase;
     }
 
     /** Returns status of the schema migration action. */
     @AppSearchResult.ResultCode
     public int getStatusCode() {
-        return mBundle.getInt(STATUS_CODE_FIELD);
+        return mStatusCode;
     }
 
     /** Gets the latency for waiting the executor. */
     public int getExecutorAcquisitionLatencyMillis() {
-        return mBundle.getInt(EXECUTOR_ACQUISITION_MILLIS_FIELD);
+        return mExecutorAcquisitionLatencyMillis;
     }
 
     /** Gets total latency for the schema migration action in milliseconds. */
     public int getTotalLatencyMillis() {
-        return mBundle.getInt(TOTAL_LATENCY_MILLIS_FIELD);
+        return mTotalLatencyMillis;
     }
 
     /** Returns GetSchema latency in milliseconds. */
     public int getGetSchemaLatencyMillis() {
-        return mBundle.getInt(GET_SCHEMA_LATENCY_MILLIS_FIELD);
+        return mGetSchemaLatencyMillis;
     }
 
     /**
@@ -138,7 +175,7 @@
      * transforming documents to new version in milliseconds.
      */
     public int getQueryAndTransformLatencyMillis() {
-        return mBundle.getInt(QUERY_AND_TRANSFORM_LATENCY_MILLIS_FIELD);
+        return mQueryAndTransformLatencyMillis;
     }
 
     /**
@@ -150,12 +187,12 @@
      * <p>Please see {@link SetSchemaRequest} for what is "incompatible".
      */
     public int getFirstSetSchemaLatencyMillis() {
-        return mBundle.getInt(FIRST_SET_SCHEMA_LATENCY_MILLIS_FIELD);
+        return mFirstSetSchemaLatencyMillis;
     }
 
     /** Returns whether the first SetSchema action success. */
     public boolean isFirstSetSchemaSuccess() {
-        return mBundle.getBoolean(IS_FIRST_SET_SCHEMA_SUCCESS_FIELD);
+        return mIsFirstSetSchemaSuccess;
     }
 
     /**
@@ -166,39 +203,56 @@
      * be set to Icing by this action.
      */
     public int getSecondSetSchemaLatencyMillis() {
-        return mBundle.getInt(SECOND_SET_SCHEMA_LATENCY_MILLIS_FIELD);
+        return mSecondSetSchemaLatencyMillis;
     }
 
     /** Returns latency of putting migrated document to Icing lib in milliseconds. */
     public int getSaveDocumentLatencyMillis() {
-        return mBundle.getInt(SAVE_DOCUMENT_LATENCY_MILLIS_FIELD);
+        return mSaveDocumentLatencyMillis;
     }
 
     /** Returns number of document that need to be migrated to another version. */
     public int getTotalNeedMigratedDocumentCount() {
-        return mBundle.getInt(TOTAL_NEED_MIGRATED_DOCUMENT_COUNT_FIELD);
+        return mTotalNeedMigratedDocumentCount;
     }
 
     /** Returns number of {@link androidx.appsearch.app.SetSchemaResponse.MigrationFailure}. */
     public int getMigrationFailureCount() {
-        return mBundle.getInt(MIGRATION_FAILURE_COUNT_FIELD);
+        return mMigrationFailureCount;
     }
 
     /** Returns number of successfully migrated and saved in Icing. */
     public int getTotalSuccessMigratedDocumentCount() {
-        return mBundle.getInt(TOTAL_SUCCESS_MIGRATED_DOCUMENT_COUNT_FIELD);
+        return mTotalSuccessMigratedDocumentCount;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        SchemaMigrationStatsCreator.writeToParcel(this, dest, flags);
     }
 
     /** Builder for {@link SchemaMigrationStats}. */
     public static class Builder {
 
-        private final Bundle mBundle;
+        String mPackageName;
+        String mDatabase;
+        int mStatusCode;
+        int mExecutorAcquisitionLatencyMillis;
+        int mTotalLatencyMillis;
+        int mGetSchemaLatencyMillis;
+        int mQueryAndTransformLatencyMillis;
+        int mFirstSetSchemaLatencyMillis;
+        boolean mIsFirstSetSchemaSuccess;
+        int mSecondSetSchemaLatencyMillis;
+        int mSaveDocumentLatencyMillis;
+        int mTotalNeedMigratedDocumentCount;
+        int mMigrationFailureCount;
+        int mTotalSuccessMigratedDocumentCount;
 
         /** Creates a {@link SchemaMigrationStats.Builder}. */
         public Builder(@NonNull String packageName, @NonNull String database) {
-            mBundle = new Bundle();
-            mBundle.putString(PACKAGE_NAME_FIELD, packageName);
-            mBundle.putString(DATABASE_FIELD, database);
+            mPackageName = Objects.requireNonNull(packageName);
+            mDatabase = Objects.requireNonNull(database);
         }
 
         /**
@@ -208,23 +262,29 @@
          * SchemaMigrationStats.
          */
         public Builder(@NonNull SchemaMigrationStats stats) {
-            mBundle = BundleUtil.deepCopy(stats.mBundle);
-        }
+            Objects.requireNonNull(stats);
 
-        /**
-         * Creates a new {@link SchemaMigrationStats.Builder} from the given Bundle
-         *
-         * <p>The bundle is NOT copied.
-         */
-        public Builder(@NonNull Bundle bundle) {
-            mBundle = Preconditions.checkNotNull(bundle);
+            mPackageName = stats.mPackageName;
+            mDatabase = stats.mDatabase;
+            mStatusCode = stats.mStatusCode;
+            mExecutorAcquisitionLatencyMillis = stats.mExecutorAcquisitionLatencyMillis;
+            mTotalLatencyMillis = stats.mTotalLatencyMillis;
+            mGetSchemaLatencyMillis = stats.mGetSchemaLatencyMillis;
+            mQueryAndTransformLatencyMillis = stats.mQueryAndTransformLatencyMillis;
+            mFirstSetSchemaLatencyMillis = stats.mFirstSetSchemaLatencyMillis;
+            mIsFirstSetSchemaSuccess = stats.mIsFirstSetSchemaSuccess;
+            mSecondSetSchemaLatencyMillis = stats.mSecondSetSchemaLatencyMillis;
+            mSaveDocumentLatencyMillis = stats.mSaveDocumentLatencyMillis;
+            mTotalNeedMigratedDocumentCount = stats.mTotalNeedMigratedDocumentCount;
+            mMigrationFailureCount = stats.mMigrationFailureCount;
+            mTotalSuccessMigratedDocumentCount = stats.mTotalSuccessMigratedDocumentCount;
         }
 
         /** Sets status code for the schema migration action. */
         @CanIgnoreReturnValue
         @NonNull
         public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
-            mBundle.putInt(STATUS_CODE_FIELD, statusCode);
+            mStatusCode = statusCode;
             return this;
         }
 
@@ -232,7 +292,7 @@
         @CanIgnoreReturnValue
         @NonNull
         public Builder setExecutorAcquisitionLatencyMillis(int executorAcquisitionLatencyMillis) {
-            mBundle.putInt(EXECUTOR_ACQUISITION_MILLIS_FIELD, executorAcquisitionLatencyMillis);
+            mExecutorAcquisitionLatencyMillis = executorAcquisitionLatencyMillis;
             return this;
         }
 
@@ -241,7 +301,7 @@
         @CanIgnoreReturnValue
         @NonNull
         public Builder setTotalLatencyMillis(int totalLatencyMillis) {
-            mBundle.putInt(TOTAL_LATENCY_MILLIS_FIELD, totalLatencyMillis);
+            mTotalLatencyMillis = totalLatencyMillis;
             return this;
         }
 
@@ -249,7 +309,7 @@
         @CanIgnoreReturnValue
         @NonNull
         public Builder setGetSchemaLatencyMillis(int getSchemaLatencyMillis) {
-            mBundle.putInt(GET_SCHEMA_LATENCY_MILLIS_FIELD, getSchemaLatencyMillis);
+            mGetSchemaLatencyMillis = getSchemaLatencyMillis;
             return this;
         }
 
@@ -261,8 +321,7 @@
         @NonNull
         public Builder setQueryAndTransformLatencyMillis(
                 int queryAndTransformLatencyMillis) {
-            mBundle.putInt(QUERY_AND_TRANSFORM_LATENCY_MILLIS_FIELD,
-                    queryAndTransformLatencyMillis);
+            mQueryAndTransformLatencyMillis = queryAndTransformLatencyMillis;
             return this;
         }
 
@@ -271,7 +330,7 @@
         @NonNull
         public Builder setFirstSetSchemaLatencyMillis(
                 int firstSetSchemaLatencyMillis) {
-            mBundle.putInt(FIRST_SET_SCHEMA_LATENCY_MILLIS_FIELD, firstSetSchemaLatencyMillis);
+            mFirstSetSchemaLatencyMillis = firstSetSchemaLatencyMillis;
             return this;
         }
 
@@ -279,7 +338,7 @@
         @CanIgnoreReturnValue
         @NonNull
         public Builder setIsFirstSetSchemaSuccess(boolean isFirstSetSchemaSuccess) {
-            mBundle.putBoolean(IS_FIRST_SET_SCHEMA_SUCCESS_FIELD, isFirstSetSchemaSuccess);
+            mIsFirstSetSchemaSuccess = isFirstSetSchemaSuccess;
             return this;
         }
 
@@ -288,7 +347,7 @@
         @NonNull
         public Builder setSecondSetSchemaLatencyMillis(
                 int secondSetSchemaLatencyMillis) {
-            mBundle.putInt(SECOND_SET_SCHEMA_LATENCY_MILLIS_FIELD, secondSetSchemaLatencyMillis);
+            mSecondSetSchemaLatencyMillis = secondSetSchemaLatencyMillis;
             return this;
         }
 
@@ -297,7 +356,7 @@
         @NonNull
         public Builder setSaveDocumentLatencyMillis(
                 int saveDocumentLatencyMillis) {
-            mBundle.putInt(SAVE_DOCUMENT_LATENCY_MILLIS_FIELD, saveDocumentLatencyMillis);
+            mSaveDocumentLatencyMillis = saveDocumentLatencyMillis;
             return this;
         }
 
@@ -305,7 +364,7 @@
         @CanIgnoreReturnValue
         @NonNull
         public Builder setTotalNeedMigratedDocumentCount(int migratedDocumentCount) {
-            mBundle.putInt(TOTAL_NEED_MIGRATED_DOCUMENT_COUNT_FIELD, migratedDocumentCount);
+            mTotalNeedMigratedDocumentCount = migratedDocumentCount;
             return this;
         }
 
@@ -314,8 +373,7 @@
         @NonNull
         public Builder setTotalSuccessMigratedDocumentCount(
                 int totalSuccessMigratedDocumentCount) {
-            mBundle.putInt(TOTAL_SUCCESS_MIGRATED_DOCUMENT_COUNT_FIELD,
-                    totalSuccessMigratedDocumentCount);
+            mTotalSuccessMigratedDocumentCount = totalSuccessMigratedDocumentCount;
             return this;
         }
 
@@ -323,7 +381,7 @@
         @CanIgnoreReturnValue
         @NonNull
         public Builder setMigrationFailureCount(int migrationFailureCount) {
-            mBundle.putInt(MIGRATION_FAILURE_COUNT_FIELD, migrationFailureCount);
+            mMigrationFailureCount = migrationFailureCount;
             return this;
         }
 
@@ -332,7 +390,21 @@
          */
         @NonNull
         public SchemaMigrationStats build() {
-            return new SchemaMigrationStats(mBundle);
+            return new SchemaMigrationStats(
+                    mPackageName,
+                    mDatabase,
+                    mStatusCode,
+                    mExecutorAcquisitionLatencyMillis,
+                    mTotalLatencyMillis,
+                    mGetSchemaLatencyMillis,
+                    mQueryAndTransformLatencyMillis,
+                    mFirstSetSchemaLatencyMillis,
+                    mIsFirstSetSchemaSuccess,
+                    mSecondSetSchemaLatencyMillis,
+                    mSaveDocumentLatencyMillis,
+                    mTotalNeedMigratedDocumentCount,
+                    mMigrationFailureCount,
+                    mTotalSuccessMigratedDocumentCount);
         }
     }
 }
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
index caa2e58..e319de9 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
@@ -16,6 +16,9 @@
 
 package androidx.appsearch.compiler;
 
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_CLASS_FACTORY_CLASS;
+import static androidx.appsearch.compiler.IntrospectionHelper.getDocumentClassFactoryForClass;
+
 import androidx.annotation.NonNull;
 
 import com.google.auto.common.GeneratedAnnotationSpecs;
@@ -36,7 +39,6 @@
  */
 class CodeGenerator {
     private final ProcessingEnvironment mEnv;
-    private final IntrospectionHelper mHelper;
     private final DocumentModel mModel;
 
     private final String mOutputPackage;
@@ -49,11 +51,10 @@
     }
 
     private CodeGenerator(
-            @NonNull ProcessingEnvironment env, @NonNull DocumentModel model)
-            throws ProcessingException {
+            @NonNull ProcessingEnvironment env,
+            @NonNull DocumentModel model) throws ProcessingException {
         // Prepare constants needed for processing
         mEnv = env;
-        mHelper = new IntrospectionHelper(env);
         mModel = model;
 
         // Perform the actual work of generating code
@@ -69,22 +70,21 @@
      * Creates factory class for any class annotated with
      * {@link androidx.appsearch.annotation.Document}
      * <p>Class Example 1:
-     *   For a class Foo annotated with @Document, we will generated a
-     *   $$__AppSearch__Foo.class under the output package.
+     * For a class Foo annotated with @Document, we will generated a
+     * $$__AppSearch__Foo.class under the output package.
      * <p>Class Example 2:
-     *   For an inner class Foo.Bar annotated with @Document, we will generated a
-     *   $$__AppSearch__Foo$$__Bar.class under the output package.
+     * For an inner class Foo.Bar annotated with @Document, we will generated a
+     * $$__AppSearch__Foo$$__Bar.class under the output package.
      */
     private TypeSpec createClass() throws ProcessingException {
         // Gets the full name of target class.
         String qualifiedName = mModel.getQualifiedDocumentClassName();
         String className = qualifiedName.substring(mOutputPackage.length() + 1);
-        ClassName genClassName = mHelper.getDocumentClassFactoryForClass(mOutputPackage, className);
+        ClassName genClassName = getDocumentClassFactoryForClass(mOutputPackage, className);
 
         TypeName genClassType = TypeName.get(mModel.getClassElement().asType());
-        TypeName factoryType = ParameterizedTypeName.get(
-                mHelper.getAppSearchClass("DocumentClassFactory"),
-                genClassType);
+        TypeName factoryType =
+                ParameterizedTypeName.get(DOCUMENT_CLASS_FACTORY_CLASS, genClassType);
 
         TypeSpec.Builder genClass = TypeSpec
                 .classBuilder(genClassName)
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java
index e8faa1e..a6c6a24 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java
@@ -15,45 +15,35 @@
  */
 package androidx.appsearch.compiler;
 
-import static androidx.appsearch.compiler.IntrospectionHelper.BUILDER_PRODUCER_CLASS;
-import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
 import static androidx.appsearch.compiler.IntrospectionHelper.generateClassHierarchy;
 import static androidx.appsearch.compiler.IntrospectionHelper.getDocumentAnnotation;
 
+import static java.util.Objects.requireNonNull;
 import static java.util.stream.Collectors.groupingBy;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
-import androidx.appsearch.compiler.IntrospectionHelper.PropertyClass;
 import androidx.appsearch.compiler.annotationwrapper.DataPropertyAnnotation;
 import androidx.appsearch.compiler.annotationwrapper.MetadataPropertyAnnotation;
 import androidx.appsearch.compiler.annotationwrapper.PropertyAnnotation;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumMap;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 import java.util.function.Predicate;
 
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
 import javax.lang.model.util.Elements;
-import javax.lang.model.util.Types;
 
 /**
  * Processes @Document annotations.
@@ -62,52 +52,20 @@
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 class DocumentModel {
-
-    /** Enumeration of fields that must be handled specially (i.e. are not properties) */
-    enum SpecialField {NAMESPACE, ID, CREATION_TIMESTAMP_MILLIS, TTL_MILLIS, SCORE}
-
-    /** Determines how the annotation processor has decided to write the value of a field. */
-    enum WriteKind {FIELD, SETTER, CREATION_METHOD}
-
     private static final String CLASS_SUFFIX = ".class";
 
     private final IntrospectionHelper mHelper;
-    private final TypeElement mClass;
-    private final Types mTypeUtil;
+
     private final Elements mElementUtil;
+
+    private final TypeElement mClass;
+
     // The name of the original class annotated with @Document
     private final String mQualifiedDocumentClassName;
-    private String mSchemaName;
-    private final Set<TypeElement> mParentTypes = new LinkedHashSet<>();
-    // All methods in the current @Document annotated class/interface, or in the generated class
-    // for AutoValue document.
-    // Warning: if you change this to a HashSet, we may choose different getters or setters from
-    // run to run, causing the generated code to bounce.
-    private final LinkedHashSet<ExecutableElement> mAllMethods;
-    // All methods in the builder class, if a builder producer is provided.
-    private final LinkedHashSet<ExecutableElement> mAllBuilderMethods;
-    // Key: Name of the element whose value is set through the setter method.
-    // Value: ExecutableElement of the setter method.
-    private final Map<String, ExecutableElement> mSetterMethods = new HashMap<>();
-    // Warning: if you change this to a HashMap, we may assign elements in a different order from
-    // run to run, causing the generated code to bounce.
-    // Keeps tracks of all AppSearch elements so we can find creation and access methods for them
-    // all
-    private final Map<String, Element> mAllAppSearchElements = new LinkedHashMap<>();
-    // Warning: if you change this to a HashMap, we may assign elements in a different order from
-    // run to run, causing the generated code to bounce.
-    // Keeps track of property elements so we don't allow multiple annotated elements of the same
-    // name
-    private final Map<String, Element> mPropertyElements = new LinkedHashMap<>();
-    private final Map<SpecialField, String> mSpecialFieldNames = new EnumMap<>(SpecialField.class);
-    private final Map<Element, WriteKind> mWriteKinds = new HashMap<>();
-    // Contains the reason why that element couldn't be written either by field or by setter.
-    private final Map<Element, ProcessingException> mWriteWhyCreationMethod =
-            new HashMap<>();
-    private ExecutableElement mChosenCreationMethod = null;
-    private List<String> mChosenCreationMethodParams = null;
-    private TypeElement mBuilderClass = null;
-    private Set<ExecutableElement> mBuilderProducers = new LinkedHashSet<>();
+
+    private final String mSchemaName;
+
+    private final LinkedHashSet<TypeElement> mParentTypes;
 
     private final LinkedHashSet<AnnotatedGetterOrField> mAnnotatedGettersAndFields;
 
@@ -133,13 +91,16 @@
         }
 
         mHelper = new IntrospectionHelper(env);
-        mClass = clazz;
-        mTypeUtil = env.getTypeUtils();
         mElementUtil = env.getElementUtils();
+        mClass = clazz;
         mQualifiedDocumentClassName = generatedAutoValueElement != null
                 ? generatedAutoValueElement.getQualifiedName().toString()
                 : clazz.getQualifiedName().toString();
-        mAnnotatedGettersAndFields = scanAnnotatedGettersAndFields(clazz, env);
+        mParentTypes = getParentSchemaTypes(clazz);
+
+        List<TypeElement> classHierarchy = generateClassHierarchy(clazz);
+        mSchemaName = computeSchemaName(classHierarchy);
+        mAnnotatedGettersAndFields = scanAnnotatedGettersAndFields(classHierarchy, env);
 
         requireNoDuplicateMetadataProperties();
         mIdAnnotatedGetterOrField = requireGetterOrFieldMatchingPredicate(
@@ -152,83 +113,17 @@
                 /* errorMessage= */"All @Document classes must have exactly one field annotated "
                         + "with @Namespace");
 
-        mAllMethods = mHelper.getAllMethods(clazz);
-        mAccessors = inferPropertyAccessors(mAnnotatedGettersAndFields, mAllMethods, mHelper);
+        LinkedHashSet<ExecutableElement> allMethods = mHelper.getAllMethods(clazz);
+        mAccessors = inferPropertyAccessors(mAnnotatedGettersAndFields, allMethods, mHelper);
         mDocumentClassCreationInfo =
                 DocumentClassCreationInfo.infer(clazz, mAnnotatedGettersAndFields, mHelper);
-
-        // Scan methods and constructors. We will need this info when processing fields to
-        // make sure the fields can be get and set.
-        Set<ExecutableElement> potentialCreationMethods = extractCreationMethods(clazz);
-        mAllBuilderMethods = mBuilderClass != null
-                ? mHelper.getAllMethods(mBuilderClass) : new LinkedHashSet<>();
-        scanFields(mClass);
-        chooseCreationMethod(potentialCreationMethods);
-    }
-
-    /**
-     * Scans all the elements in typeElement to find a builder producer. If found, set
-     * mBuilderProducers and mBuilderClass to the builder producer candidates and the builder class
-     * respectively.
-     *
-     * @throws ProcessingException if there are more than one elements annotated with
-     *                             {@code @Document.BuilderProducer}, or if the builder producer
-     *                             element is not a visible static
-     *                             method or a class.
-     */
-    private void extractBuilderProducer(TypeElement typeElement)
-            throws ProcessingException {
-        for (Element child : typeElement.getEnclosedElements()) {
-            boolean isAnnotated = false;
-            for (AnnotationMirror annotation : child.getAnnotationMirrors()) {
-                if (annotation.getAnnotationType().toString().equals(
-                        BUILDER_PRODUCER_CLASS.canonicalName())) {
-                    isAnnotated = true;
-                    break;
-                }
-            }
-            if (!isAnnotated) {
-                continue;
-            }
-            if (child.getKind() != ElementKind.METHOD && child.getKind() != ElementKind.CLASS) {
-                // Since @Document.BuilderProducer is configured with
-                // @Target({ElementType.METHOD, ElementType.TYPE}), it's not possible to reach here.
-                throw new ProcessingException("Builder producer must be a method or a class",
-                        child);
-            }
-            if (mBuilderClass != null) {
-                throw new ProcessingException("Found duplicated builder producer", typeElement);
-            }
-            Set<Modifier> methodModifiers = child.getModifiers();
-            if (!methodModifiers.contains(Modifier.STATIC)) {
-                throw new ProcessingException("Builder producer must be static", child);
-            }
-            if (methodModifiers.contains(Modifier.PRIVATE)) {
-                throw new ProcessingException("Builder producer cannot be private", child);
-            }
-            if (child.getKind() == ElementKind.METHOD) {
-                ExecutableElement method = (ExecutableElement) child;
-                mBuilderProducers.add(method);
-                mBuilderClass = (TypeElement) mTypeUtil.asElement(method.getReturnType());
-            } else {
-                // child is a class, so extract all of its constructors as builder producer
-                // candidates. The validity of the constructor will be checked later when we
-                // choose the right creation method.
-                mBuilderClass = (TypeElement) child;
-                for (Element builderProducer : mBuilderClass.getEnclosedElements()) {
-                    if (builderProducer.getKind() == ElementKind.CONSTRUCTOR) {
-                        mBuilderProducers.add((ExecutableElement) builderProducer);
-                    }
-                }
-            }
-        }
     }
 
     private static LinkedHashSet<AnnotatedGetterOrField> scanAnnotatedGettersAndFields(
-            @NonNull TypeElement clazz,
+            @NonNull List<TypeElement> hierarchy,
             @NonNull ProcessingEnvironment env) throws ProcessingException {
         AnnotatedGetterAndFieldAccumulator accumulator = new AnnotatedGetterAndFieldAccumulator();
-        for (TypeElement type : generateClassHierarchy(clazz)) {
+        for (TypeElement type : hierarchy) {
             for (Element enclosedElement : type.getEnclosedElements()) {
                 AnnotatedGetterOrField getterOrField =
                         AnnotatedGetterOrField.tryCreateFor(enclosedElement, env);
@@ -285,29 +180,6 @@
                 .orElseThrow(() -> new ProcessingException(errorMessage, mClass));
     }
 
-    private Set<ExecutableElement> extractCreationMethods(TypeElement typeElement)
-            throws ProcessingException {
-        extractBuilderProducer(typeElement);
-        // If a builder producer is provided, then only the builder can be used as a creation
-        // method.
-        if (mBuilderClass != null) {
-            return Collections.unmodifiableSet(mBuilderProducers);
-        }
-
-        Set<ExecutableElement> creationMethods = new LinkedHashSet<>();
-        for (Element child : typeElement.getEnclosedElements()) {
-            if (child.getKind() == ElementKind.CONSTRUCTOR) {
-                creationMethods.add((ExecutableElement) child);
-            } else if (child.getKind() == ElementKind.METHOD) {
-                ExecutableElement method = (ExecutableElement) child;
-                if (isFactoryMethod(method)) {
-                    creationMethods.add(method);
-                }
-            }
-        }
-        return Collections.unmodifiableSet(creationMethods);
-    }
-
     /**
      * Tries to create an {@link DocumentModel} from the given {@link Element}.
      *
@@ -360,11 +232,6 @@
         return mParentTypes;
     }
 
-    @NonNull
-    public Map<String, Element> getAllElements() {
-        return Collections.unmodifiableMap(mAllAppSearchElements);
-    }
-
     /**
      * Returns all getters/fields (declared or inherited) annotated with some
      * {@link PropertyAnnotation}.
@@ -409,93 +276,6 @@
     }
 
     /**
-     * @deprecated Use {@link #getAnnotatedGettersAndFields()} instead.
-     */
-    @Deprecated
-    @NonNull
-    public Map<String, Element> getPropertyElements() {
-        return Collections.unmodifiableMap(mPropertyElements);
-    }
-
-    @Nullable
-    public String getSpecialFieldName(SpecialField field) {
-        return mSpecialFieldNames.get(field);
-    }
-
-    @Nullable
-    public WriteKind getElementWriteKind(String elementName) {
-        Element element = mAllAppSearchElements.get(elementName);
-        return mWriteKinds.get(element);
-    }
-
-    @Nullable
-    public ExecutableElement getSetterForElement(String elementName) {
-        return mSetterMethods.get(elementName);
-    }
-
-    /**
-     * Finds the AppSearch name for the given property.
-     *
-     * <p>This is usually the name of the field in Java, but may be changed if the developer
-     * specifies a different 'name' parameter in the annotation.
-     *
-     * @deprecated Use {@link #getAnnotatedGettersAndFields()} and
-     * {@link DataPropertyAnnotation#getName()} ()} instead.
-     */
-    @Deprecated
-    @NonNull
-    public String getPropertyName(@NonNull Element property) throws ProcessingException {
-        AnnotationMirror annotation = getPropertyAnnotation(property);
-        Map<String, Object> params = mHelper.getAnnotationParams(annotation);
-        String propertyName = params.get("name").toString();
-        if (propertyName.isEmpty()) {
-            propertyName = getNormalizedElementName(property);
-        }
-        return propertyName;
-    }
-
-    /**
-     * Returns the first found AppSearch property annotation element from the input element's
-     * annotations.
-     *
-     * @throws ProcessingException if no AppSearch property annotation is found.
-     * @deprecated Use {@link #getAnnotatedGettersAndFields()} and
-     * {@link AnnotatedGetterOrField#getAnnotation()} instead.
-     */
-    @Deprecated
-    @NonNull
-    public AnnotationMirror getPropertyAnnotation(@NonNull Element element)
-            throws ProcessingException {
-        Objects.requireNonNull(element);
-        Set<String> propertyClassPaths = new HashSet<>();
-        for (PropertyClass propertyClass : PropertyClass.values()) {
-            propertyClassPaths.add(propertyClass.getClassFullPath());
-        }
-        for (AnnotationMirror annotation : element.getAnnotationMirrors()) {
-            String annotationFq = annotation.getAnnotationType().toString();
-            if (propertyClassPaths.contains(annotationFq)) {
-                return annotation;
-            }
-        }
-        throw new ProcessingException("Missing AppSearch property annotation.", element);
-    }
-
-    @NonNull
-    public ExecutableElement getChosenCreationMethod() {
-        return mChosenCreationMethod;
-    }
-
-    @NonNull
-    public List<String> getChosenCreationMethodParams() {
-        return Collections.unmodifiableList(mChosenCreationMethodParams);
-    }
-
-    @Nullable
-    public TypeElement getBuilderClass() {
-        return mBuilderClass;
-    }
-
-    /**
      * Infers the {@link PropertyAccessor} for each of the {@link AnnotatedGetterOrField}.
      *
      * <p>Each accessor may be the {@link AnnotatedGetterOrField} itself or some other non-private
@@ -515,493 +295,30 @@
         return accessors;
     }
 
-    private boolean isFactoryMethod(ExecutableElement method) {
-        Set<Modifier> methodModifiers = method.getModifiers();
-        return methodModifiers.contains(Modifier.STATIC)
-                && !methodModifiers.contains(Modifier.PRIVATE)
-                && mTypeUtil.isSameType(method.getReturnType(), mClass.asType());
-    }
-
     /**
-     * Scan the annotations of a field to determine the fields type and handle it accordingly
-     *
-     * @param childElement the member of class elements currently being scanned
-     * @deprecated Rely on {@link #mAnnotatedGettersAndFields} instead of
-     * {@link #mAllAppSearchElements} and {@link #mSpecialFieldNames}.
+     * Returns the parent types mentioned within the {@code @Document} annotation.
      */
-    @Deprecated
-    private void scanAnnotatedField(@NonNull Element childElement) throws ProcessingException {
-        String fieldName = childElement.getSimpleName().toString();
-
-        // a property field shouldn't be able to override a special field
-        if (mSpecialFieldNames.containsValue(fieldName)) {
+    @NonNull
+    private LinkedHashSet<TypeElement> getParentSchemaTypes(
+            @NonNull TypeElement documentClass) throws ProcessingException {
+        AnnotationMirror documentAnnotation = requireNonNull(getDocumentAnnotation(documentClass));
+        Map<String, Object> params = mHelper.getAnnotationParams(documentAnnotation);
+        LinkedHashSet<TypeElement> parentsSchemaTypes = new LinkedHashSet<>();
+        Object parentsParam = params.get("parent");
+        if (parentsParam instanceof List) {
+            for (Object parent : (List<?>) parentsParam) {
+                String parentClassName = parent.toString();
+                parentClassName = parentClassName.substring(0,
+                        parentClassName.length() - CLASS_SUFFIX.length());
+                parentsSchemaTypes.add(mElementUtil.getTypeElement(parentClassName));
+            }
+        }
+        if (!parentsSchemaTypes.isEmpty() && params.get("name").toString().isEmpty()) {
             throw new ProcessingException(
-                    "Non-annotated field overriding special annotated fields named: "
-                            + fieldName, mAllAppSearchElements.get(fieldName));
-        }
-
-        // no annotation mirrors -> non-indexable field
-        for (AnnotationMirror annotation : childElement.getAnnotationMirrors()) {
-            String annotationFq = annotation.getAnnotationType().toString();
-            if (!annotationFq.startsWith(DOCUMENT_ANNOTATION_CLASS.canonicalName())
-                    || annotationFq.equals(BUILDER_PRODUCER_CLASS.canonicalName())) {
-                continue;
-            }
-            if (childElement.getKind() == ElementKind.CLASS) {
-                continue;
-            }
-
-            if (annotationFq.equals(MetadataPropertyAnnotation.ID.getClassName().canonicalName())) {
-                if (mSpecialFieldNames.containsKey(SpecialField.ID)) {
-                    throw new ProcessingException(
-                            "Class hierarchy contains multiple fields annotated @Id",
-                            childElement);
-                }
-                mSpecialFieldNames.put(SpecialField.ID, fieldName);
-            } else if (annotationFq.equals(
-                    MetadataPropertyAnnotation.NAMESPACE.getClassName().canonicalName())) {
-                if (mSpecialFieldNames.containsKey(SpecialField.NAMESPACE)) {
-                    throw new ProcessingException(
-                            "Class hierarchy contains multiple fields annotated @Namespace",
-                            childElement);
-                }
-                mSpecialFieldNames.put(SpecialField.NAMESPACE, fieldName);
-            } else if (annotationFq.equals(
-                    MetadataPropertyAnnotation.CREATION_TIMESTAMP_MILLIS
-                            .getClassName()
-                            .canonicalName())) {
-                if (mSpecialFieldNames.containsKey(SpecialField.CREATION_TIMESTAMP_MILLIS)) {
-                    throw new ProcessingException("Class hierarchy contains multiple fields "
-                            + "annotated @CreationTimestampMillis", childElement);
-                }
-                mSpecialFieldNames.put(
-                        SpecialField.CREATION_TIMESTAMP_MILLIS, fieldName);
-            } else if (annotationFq.equals(
-                    MetadataPropertyAnnotation.TTL_MILLIS.getClassName().canonicalName())) {
-                if (mSpecialFieldNames.containsKey(SpecialField.TTL_MILLIS)) {
-                    throw new ProcessingException(
-                            "Class hierarchy contains multiple fields annotated @TtlMillis",
-                            childElement);
-                }
-                mSpecialFieldNames.put(SpecialField.TTL_MILLIS, fieldName);
-            } else if (annotationFq.equals(
-                    MetadataPropertyAnnotation.SCORE.getClassName().canonicalName())) {
-                if (mSpecialFieldNames.containsKey(SpecialField.SCORE)) {
-                    throw new ProcessingException(
-                            "Class hierarchy contains multiple fields annotated @Score",
-                            childElement);
-                }
-                mSpecialFieldNames.put(SpecialField.SCORE, fieldName);
-            } else {
-                PropertyClass propertyClass = getPropertyClass(annotationFq);
-                if (propertyClass != null) {
-                    // A property must either:
-                    //   1. be unique
-                    //   2. override a property from the Java parent while maintaining the same
-                    //      AppSearch property name
-                    checkFieldTypeForPropertyAnnotation(childElement, propertyClass);
-                    // It's assumed that parent types, in the context of Java's type system,
-                    // are always visited before child types, so existingProperty must come
-                    // from the parent type. To make this assumption valid, the result
-                    // returned by generateClassHierarchy must put parent types before child
-                    // types.
-                    Element existingProperty = mPropertyElements.get(fieldName);
-                    if (existingProperty != null) {
-                        if (!mTypeUtil.isSameType(
-                                existingProperty.asType(), childElement.asType())) {
-                            throw new ProcessingException(
-                                    "Cannot override a property with a different type",
-                                    childElement);
-                        }
-                        if (!getPropertyName(existingProperty).equals(getPropertyName(
-                                childElement))) {
-                            throw new ProcessingException(
-                                    "Cannot override a property with a different name",
-                                    childElement);
-                        }
-                    }
-                    mPropertyElements.put(fieldName, childElement);
-                }
-            }
-
-            mAllAppSearchElements.put(fieldName, childElement);
-        }
-    }
-
-    /**
-     * Scans all the fields of the class, as well as superclasses annotated with @Document,
-     * to get AppSearch fields such as id
-     *
-     * @param element the class to scan
-     */
-    private void scanFields(@NonNull TypeElement element) throws ProcessingException {
-        AnnotationMirror documentAnnotation = getDocumentAnnotation(element);
-        if (documentAnnotation != null) {
-            Map<String, Object> params = mHelper.getAnnotationParams(documentAnnotation);
-            Object parents = params.get("parent");
-            if (parents instanceof List) {
-                for (Object parent : (List<?>) parents) {
-                    String parentClassName = parent.toString();
-                    parentClassName = parentClassName.substring(0,
-                            parentClassName.length() - CLASS_SUFFIX.length());
-                    mParentTypes.add(mElementUtil.getTypeElement(parentClassName));
-                }
-            }
-            if (!mParentTypes.isEmpty() && params.get("name").toString().isEmpty()) {
-                throw new ProcessingException(
-                        "All @Document classes with a parent must explicitly provide a name",
-                        mClass);
-            }
-        }
-
-        List<TypeElement> hierarchy = generateClassHierarchy(element);
-
-        for (TypeElement clazz : hierarchy) {
-            List<? extends Element> enclosedElements = clazz.getEnclosedElements();
-            for (Element childElement : enclosedElements) {
-                scanAnnotatedField(childElement);
-            }
-        }
-
-        // Every document must always have a namespace
-        if (!mSpecialFieldNames.containsKey(SpecialField.NAMESPACE)) {
-            throw new ProcessingException(
-                    "All @Document classes must have exactly one field annotated with @Namespace",
+                    "All @Document classes with a parent must explicitly provide a name",
                     mClass);
         }
-
-        // Every document must always have an ID
-        if (!mSpecialFieldNames.containsKey(SpecialField.ID)) {
-            throw new ProcessingException(
-                    "All @Document classes must have exactly one field annotated with @Id",
-                    mClass);
-        }
-
-        mSchemaName = computeSchemaName(hierarchy);
-
-        for (Element appSearchField : mAllAppSearchElements.values()) {
-            chooseWriteKind(appSearchField);
-        }
-    }
-
-    /**
-     * Checks whether property's data type matches the {@code androidx.appsearch.annotation
-     * .Document} property annotation's requirement.
-     *
-     * @throws ProcessingException if data type doesn't match property annotation's requirement.
-     */
-    void checkFieldTypeForPropertyAnnotation(@NonNull Element property,
-            PropertyClass propertyClass) throws ProcessingException {
-        switch (propertyClass) {
-            case BOOLEAN_PROPERTY_CLASS:
-                if (mHelper.isFieldOfExactType(property, mHelper.mBooleanBoxType,
-                        mHelper.mBooleanPrimitiveType)) {
-                    return;
-                }
-                break;
-            case BYTES_PROPERTY_CLASS:
-                if (mHelper.isFieldOfExactType(property, mHelper.mByteBoxType,
-                        mHelper.mBytePrimitiveType, mHelper.mByteBoxArrayType,
-                        mHelper.mBytePrimitiveArrayType)) {
-                    return;
-                }
-                break;
-            case DOCUMENT_PROPERTY_CLASS:
-                if (mHelper.isFieldOfDocumentType(property)) {
-                    return;
-                }
-                break;
-            case DOUBLE_PROPERTY_CLASS:
-                if (mHelper.isFieldOfExactType(property, mHelper.mDoubleBoxType,
-                        mHelper.mDoublePrimitiveType, mHelper.mFloatBoxType,
-                        mHelper.mFloatPrimitiveType)) {
-                    return;
-                }
-                break;
-            case LONG_PROPERTY_CLASS:
-                if (mHelper.isFieldOfExactType(property, mHelper.mIntegerBoxType,
-                        mHelper.mIntPrimitiveType, mHelper.mLongBoxType,
-                        mHelper.mLongPrimitiveType)) {
-                    return;
-                }
-                break;
-            case STRING_PROPERTY_CLASS:
-                if (mHelper.isFieldOfExactType(property, mHelper.mStringType)) {
-                    return;
-                }
-                break;
-            default:
-                // do nothing
-        }
-        throw new ProcessingException(
-                "Property Annotation " + propertyClass.getClassFullPath() + " doesn't accept the "
-                        + "data type of property field " + property.getSimpleName(), property);
-    }
-
-    /**
-     * Returns the {@link PropertyClass} with {@code annotationFq} as full class path, and {@code
-     * null} if failed to find such a {@link PropertyClass}.
-     */
-    @Nullable
-    private PropertyClass getPropertyClass(@Nullable String annotationFq) {
-        for (PropertyClass propertyClass : PropertyClass.values()) {
-            if (propertyClass.isPropertyClass(annotationFq)) {
-                return propertyClass;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Chooses how to write a given field.
-     *
-     * <p>The writing strategy can be one of: visible mutable field, or visible setter, or visible
-     * creation method accepting at minimum all fields that aren't mutable and have no visible
-     * setter.
-     */
-    private void chooseWriteKind(@NonNull Element field) {
-        // TODO(b/300114568): Carve out better distinction b/w the different write strategies
-        Set<Modifier> modifiers = field.getModifiers();
-        // Choose set access
-        if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.FINAL)
-                || modifiers.contains(Modifier.STATIC) || field.getKind() == ElementKind.METHOD
-                || mBuilderClass != null) {
-            // Try to find a setter. If we can't find one, mark the WriteKind as {@code
-            // CREATION_METHOD}. We don't know if this is true yet, the creation methods will be
-            // inspected in a subsequent pass.
-            try {
-                findSetter(field);
-                mWriteKinds.put(field, WriteKind.SETTER);
-            } catch (ProcessingException e) {
-                // We'll look for a creation method, so we may still be able to set this field,
-                // but it's more likely the developer configured the setter incorrectly. Keep
-                // the exception around to include it in the report if no creation method is found.
-                mWriteWhyCreationMethod.put(field, e);
-                mWriteKinds.put(field, WriteKind.CREATION_METHOD);
-            }
-        } else {
-            mWriteKinds.put(field, WriteKind.FIELD);
-        }
-    }
-
-    private void chooseCreationMethod(Set<ExecutableElement> creationMethods)
-            throws ProcessingException {
-        // Maps field name to Element.
-        // If this is changed to a HashSet, we might report errors to the developer in a different
-        // order about why a field was written via creation method.
-        Map<String, Element> creationMethodWrittenFields = new LinkedHashMap<>();
-        for (Map.Entry<Element, WriteKind> it : mWriteKinds.entrySet()) {
-            if (it.getValue() == WriteKind.CREATION_METHOD) {
-                String name = it.getKey().getSimpleName().toString();
-                creationMethodWrittenFields.put(name, it.getKey());
-            }
-        }
-
-        // Maps normalized field name to real field name.
-        Map<String, String> normalizedToRawFieldName = new HashMap<>();
-        for (Element field : mAllAppSearchElements.values()) {
-            normalizedToRawFieldName.put(getNormalizedElementName(field),
-                    field.getSimpleName().toString());
-        }
-
-        Map<ExecutableElement, String> whyNotCreationMethod = new HashMap<>();
-        creationMethodSearch:
-        for (ExecutableElement method : creationMethods) {
-            if (method.getModifiers().contains(Modifier.PRIVATE)) {
-                whyNotCreationMethod.put(method, "Creation method is private");
-                continue creationMethodSearch;
-            }
-            // The field name of each field that goes into the creation method, in the order they
-            // are declared in the creation method signature.
-            List<String> creationMethodParamFields = new ArrayList<>();
-            Set<String> remainingFields = new HashSet<>(creationMethodWrittenFields.keySet());
-            for (VariableElement parameter : method.getParameters()) {
-                String paramName = parameter.getSimpleName().toString();
-                String fieldName = normalizedToRawFieldName.get(paramName);
-                if (fieldName == null) {
-                    whyNotCreationMethod.put(
-                            method,
-                            "Parameter \"" + paramName + "\" is not an AppSearch parameter; don't "
-                                    + "know how to supply it.");
-                    continue creationMethodSearch;
-                }
-                remainingFields.remove(fieldName);
-                creationMethodParamFields.add(fieldName);
-            }
-            if (!remainingFields.isEmpty()) {
-                whyNotCreationMethod.put(
-                        method,
-                        "This method doesn't have parameters for the following fields: "
-                                + remainingFields);
-                continue creationMethodSearch;
-            }
-
-            // If the field is set in the constructor, choose creation method for the write kind
-            for (String param : creationMethodParamFields) {
-                for (Element appSearchField : mAllAppSearchElements.values()) {
-                    if (appSearchField.getSimpleName().toString().equals(param)) {
-                        mWriteKinds.put(appSearchField, WriteKind.CREATION_METHOD);
-                        break;
-                    }
-                }
-            }
-
-            // Found one!
-            mChosenCreationMethod = method;
-            mChosenCreationMethodParams = creationMethodParamFields;
-            return;
-        }
-
-        // If we got here, we couldn't find any creation methods.
-        ProcessingException e =
-                new ProcessingException(
-                        "Failed to find any suitable creation methods to build class \""
-                                + mClass.getQualifiedName()
-                                + "\". See warnings for details.",
-                        mClass);
-
-        // Inform the developer why we started looking for creation methods in the first place.
-        for (Element field : creationMethodWrittenFields.values()) {
-            ProcessingException warning = mWriteWhyCreationMethod.get(field);
-            if (warning != null) {
-                e.addWarning(warning);
-            }
-        }
-
-        // Inform the developer about why each creation method we considered was rejected.
-        for (Map.Entry<ExecutableElement, String> it : whyNotCreationMethod.entrySet()) {
-            ProcessingException warning = new ProcessingException(
-                    "Cannot use this creation method to construct the class: " + it.getValue(),
-                    it.getKey());
-            e.addWarning(warning);
-        }
-
-        throw e;
-    }
-
-    /**
-     * Finds setter function for a private field, or for a property defined by a annotated getter
-     * method.
-     */
-    private void findSetter(@NonNull Element element) throws ProcessingException {
-        String elementName = element.getSimpleName().toString();
-        // We can't report setter failure until we've searched the creation methods, so this
-        // message is anticipatory and should be buffered by the caller.
-        String error;
-        if (mBuilderClass != null) {
-            error = "Element cannot be written directly because a builder producer is provided";
-        } else if (element.getKind() == ElementKind.METHOD) {
-            error = "Element cannot be written directly because it is an annotated getter";
-        } else {
-            error = "Field cannot be written directly because it is private, final, or static";
-        }
-        error += ", and we failed to find a suitable setter for \"" + elementName + "\". "
-                + "Trying to find a suitable creation method.";
-        ProcessingException e = new ProcessingException(error,
-                mAllAppSearchElements.get(elementName));
-
-        // When using the builder pattern, setters can only come from the builder.
-        Set<ExecutableElement> methods;
-        if (mBuilderClass != null) {
-            methods = mAllBuilderMethods;
-        } else {
-            methods = mAllMethods;
-        }
-        for (ExecutableElement method : methods) {
-            String methodName = method.getSimpleName().toString();
-            String normalizedElementName = getNormalizedElementName(element);
-            if (methodName.equals(normalizedElementName)
-                    || methodName.equals("set"
-                    + normalizedElementName.substring(0, 1).toUpperCase()
-                    + normalizedElementName.substring(1))) {
-                if (method.getModifiers().contains(Modifier.PRIVATE)) {
-                    e.addWarning(new ProcessingException(
-                            "Setter cannot be used: private visibility", method));
-                    continue;
-                }
-                if (method.getParameters().size() != 1) {
-                    e.addWarning(new ProcessingException(
-                            "Setter cannot be used: takes " + method.getParameters().size()
-                                    + " parameters instead of 1",
-                            method));
-                    continue;
-                }
-                // Found one!
-                mSetterMethods.put(elementName, method);
-                return;
-            }
-        }
-
-        // Broke out of the loop without finding anything.
-        throw e;
-    }
-
-    /**
-     * Produces the canonical name of a field element.
-     *
-     * @see #getNormalizedElementName(Element)
-     */
-    private String getNormalizedFieldElementName(Element fieldElement) {
-        String fieldName = fieldElement.getSimpleName().toString();
-
-        if (fieldName.length() < 2) {
-            return fieldName;
-        }
-
-        // Handle convention of having field names start with m
-        // (e.g. String mName; public String getName())
-        if (fieldName.charAt(0) == 'm' && Character.isUpperCase(fieldName.charAt(1))) {
-            return fieldName.substring(1, 2).toLowerCase() + fieldName.substring(2);
-        }
-
-        // Handle convention of having field names start with _
-        // (e.g. String _name; public String getName())
-        if (fieldName.charAt(0) == '_'
-                && fieldName.charAt(1) != '_'
-                && Character.isLowerCase(fieldName.charAt(1))) {
-            return fieldName.substring(1);
-        }
-
-        // Handle convention of having field names end with _
-        // (e.g. String name_; public String getName())
-        if (fieldName.charAt(fieldName.length() - 1) == '_'
-                && fieldName.charAt(fieldName.length() - 2) != '_') {
-            return fieldName.substring(0, fieldName.length() - 1);
-        }
-
-        return fieldName;
-    }
-
-    /**
-     * Produces the canonical name of a method element.
-     *
-     * @see #getNormalizedElementName(Element)
-     */
-    private String getNormalizedMethodElementName(Element methodElement) {
-        String methodName = methodElement.getSimpleName().toString();
-
-        // If this property is defined by an annotated getter, then we can remove the prefix
-        // "get" or "is" if possible.
-        if (methodName.startsWith("get") && methodName.length() > 3) {
-            methodName = methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
-        } else if (mHelper.isFieldOfBooleanType(methodElement) && methodName.startsWith("is")
-                && methodName.length() > 2) {
-            // "is" is a valid getter prefix for boolean property.
-            methodName = methodName.substring(2, 3).toLowerCase() + methodName.substring(3);
-        }
-        // Return early because the rest normalization procedures do not apply to getters.
-        return methodName;
-    }
-
-    /**
-     * Produces the canonical name of a element (which is used as the default property name as
-     * well as to find accessors) by removing prefixes and suffixes of common conventions.
-     */
-    private String getNormalizedElementName(Element property) {
-        if (property.getKind() == ElementKind.METHOD) {
-            return getNormalizedMethodElementName(property);
-        }
-        return getNormalizedFieldElementName(property);
+        return parentsSchemaTypes;
     }
 
     /**
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 1947dea..8bb9788 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
@@ -89,6 +89,9 @@
     public static final ClassName BUILDER_PRODUCER_CLASS =
             DOCUMENT_ANNOTATION_CLASS.nestedClass("BuilderProducer");
 
+    static final ClassName DOCUMENT_CLASS_FACTORY_CLASS =
+            ClassName.get(APPSEARCH_PKG, "DocumentClassFactory");
+
     public final TypeMirror mStringType;
     public final TypeMirror mLongPrimitiveType;
     public final TypeMirror mIntPrimitiveType;
@@ -172,7 +175,8 @@
     }
 
     /** Checks whether the property data type is one of the valid types. */
-    public boolean isFieldOfExactType(Element property, TypeMirror... validTypes) {
+    public boolean isFieldOfExactType(
+            @NonNull Element property, @NonNull TypeMirror... validTypes) {
         TypeMirror propertyType = getPropertyType(property);
         for (TypeMirror validType : validTypes) {
             if (propertyType.getKind() == TypeKind.ARRAY) {
@@ -193,31 +197,14 @@
     }
 
     /** Checks whether the property data type is of boolean type. */
-    public boolean isFieldOfBooleanType(Element property) {
+    public boolean isFieldOfBooleanType(@NonNull Element property) {
         return isFieldOfExactType(property, mBooleanBoxType, mBooleanPrimitiveType);
     }
 
     /**
-     * Checks whether the property data class has {@code androidx.appsearch.annotation.Document
-     * .DocumentProperty} annotation.
+     * Returns the annotation's params as a map. Includes the default values.
      */
-    public boolean isFieldOfDocumentType(Element property) {
-        TypeMirror propertyType = getPropertyType(property);
-
-        AnnotationMirror documentAnnotation = null;
-
-        if (propertyType.getKind() == TypeKind.ARRAY) {
-            documentAnnotation = getDocumentAnnotation(
-                    mTypeUtils.asElement(((ArrayType) propertyType).getComponentType()));
-        } else if (mTypeUtils.isAssignable(mTypeUtils.erasure(propertyType), mCollectionType)) {
-            documentAnnotation = getDocumentAnnotation(mTypeUtils.asElement(
-                    ((DeclaredType) propertyType).getTypeArguments().get(0)));
-        } else {
-            documentAnnotation = getDocumentAnnotation(mTypeUtils.asElement(propertyType));
-        }
-        return documentAnnotation != null;
-    }
-
+    @NonNull
     public Map<String, Object> getAnnotationParams(@NonNull AnnotationMirror annotation) {
         Map<? extends ExecutableElement, ? extends AnnotationValue> values =
                 mEnv.getElementUtils().getElementValuesWithDefaults(annotation);
@@ -251,10 +238,6 @@
         return getDocumentClassFactoryForClass(clazz.packageName(), className);
     }
 
-    public ClassName getAppSearchClass(String clazz, String... nested) {
-        return ClassName.get(APPSEARCH_PKG, clazz, nested);
-    }
-
     /**
      * Returns all the methods within a class, whether inherited or declared directly.
      *
@@ -454,27 +437,4 @@
                     hierarchy, visited);
         }
     }
-
-    enum PropertyClass {
-        BOOLEAN_PROPERTY_CLASS("androidx.appsearch.annotation.Document.BooleanProperty"),
-        BYTES_PROPERTY_CLASS("androidx.appsearch.annotation.Document.BytesProperty"),
-        DOCUMENT_PROPERTY_CLASS("androidx.appsearch.annotation.Document.DocumentProperty"),
-        DOUBLE_PROPERTY_CLASS("androidx.appsearch.annotation.Document.DoubleProperty"),
-        LONG_PROPERTY_CLASS("androidx.appsearch.annotation.Document.LongProperty"),
-        STRING_PROPERTY_CLASS("androidx.appsearch.annotation.Document.StringProperty");
-
-        private final String mClassFullPath;
-
-        PropertyClass(String classFullPath) {
-            mClassFullPath = classFullPath;
-        }
-
-        String getClassFullPath() {
-            return mClassFullPath;
-        }
-
-        boolean isPropertyClass(String annotationFq) {
-            return mClassFullPath.equals(annotationFq);
-        }
-    }
 }
diff --git a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
index 5690a38..22910ce 100644
--- a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
+++ b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
@@ -96,7 +96,7 @@
     }
 
     @Test
-    public void testAutoValueInheritance() throws Exception {
+    public void testAutoValueInheritance() {
         Compilation docExtendsAutoValueDoc = compile(
                 "import com.google.auto.value.AutoValue;\n"
                         + "import com.google.auto.value.AutoValue.*;\n"
@@ -144,7 +144,7 @@
     }
 
     @Test
-    public void testSuperClassErrors() throws Exception {
+    public void testSuperClassErrors() {
         Compilation specialFieldReassigned = compile(
                 "@Document\n"
                         + "public class Gift {\n"
@@ -169,27 +169,6 @@
                 "Property type must stay consistent when overriding annotated "
                         + "members but changed from @Id -> @StringProperty");
 
-        Compilation nonAnnotatedFieldHasSameName = compile(
-                "@Document\n"
-                        + "public class Gift {\n"
-                        + "  @Document.Namespace String namespace;\n"
-                        + "  @Document.Id String id;\n"
-                        + "  Gift(String id, String namespace) {\n"
-                        + "    this.id = id;\n"
-                        + "    this.namespace = namespace;\n"
-                        + "  }\n"
-                        + "}\n"
-                        + "@Document\n"
-                        + "class CoolGift extends Gift {\n"
-                        + "  String id;\n"
-                        + "  CoolGift(String id, String namespace) {\n"
-                        + "    super(id, namespace);\n"
-                        + "  }\n"
-                        + "  public String getId() { return id; }\n"
-                        + "}\n");
-        assertThat(nonAnnotatedFieldHasSameName).hadErrorContaining(
-                "Non-annotated field overriding special annotated fields named: id");
-
         //error on collision
         Compilation idCollision = compile(
                 "@Document\n"
@@ -1209,7 +1188,7 @@
     }
 
     @Test
-    public void testInvalidLongPropertyIndexingType() throws Exception {
+    public void testInvalidLongPropertyIndexingType() {
         // AppSearchSchema requires Android and is not available in this desktop test, so we cheat
         // by using the integer constants directly.
         Compilation compilation = compile(
@@ -1241,7 +1220,7 @@
     }
 
     @Test
-    public void testRepeatedPropertyJoinableType_throwsError() throws Exception {
+    public void testRepeatedPropertyJoinableType_throwsError() {
         Compilation compilation = compile(
                 "import java.util.*;\n"
                         + "@Document\n"
@@ -1711,7 +1690,7 @@
     }
 
     @Test
-    public void testPolymorphismOverrideExtendedPropertyInvalid() throws Exception {
+    public void testPolymorphismOverrideExtendedPropertyInvalid() {
         // Overridden properties cannot change the names.
         Compilation compilation = compile(
                 "@Document\n"
@@ -1828,7 +1807,7 @@
     }
 
     @Test
-    public void testPolymorphismChildTypeWithoutName() throws Exception {
+    public void testPolymorphismChildTypeWithoutName() {
         Compilation compilation = compile(
                 "@Document\n"
                         + "class Parent {\n"
@@ -1922,7 +1901,7 @@
     }
 
     @Test
-    public void testAnnotationOnGetterWithoutFactory() throws Exception {
+    public void testAnnotationOnGetterWithoutFactory() {
         // An interface without any factory method is not able to initialize, as interfaces do
         // not have constructors.
         Compilation compilation = compile(
@@ -2098,7 +2077,7 @@
     }
 
     @Test
-    public void testSameNameGetterAndFieldAnnotatingBothButGetterIsPrivate() throws Exception {
+    public void testSameNameGetterAndFieldAnnotatingBothButGetterIsPrivate() {
         Compilation compilation = compile(
                 "@Document\n"
                         + "public class Gift {\n"
@@ -2168,7 +2147,7 @@
     }
 
     @Test
-    public void testGetterWithParameterCannotBeUsed() throws Exception {
+    public void testGetterWithParameterCannotBeUsed() {
         Compilation compilation = compile(
                 "@Document\n"
                         + "public class Gift {\n"
@@ -2185,7 +2164,7 @@
     }
 
     @Test
-    public void testPrivateGetterCannotBeUsed() throws Exception {
+    public void testPrivateGetterCannotBeUsed() {
         Compilation compilation = compile(
                 "@Document\n"
                         + "public class Gift {\n"
@@ -2224,7 +2203,7 @@
     }
 
     @Test
-    public void testGetterWithWrongReturnType() throws Exception {
+    public void testGetterWithWrongReturnType() {
         Compilation compilation = compile(
                 "@Document\n"
                         + "public class Gift {\n"
@@ -2571,7 +2550,7 @@
     }
 
     @Test
-    public void testCreationByBuilderErrors() throws Exception {
+    public void testCreationByBuilderErrors() {
         // Cannot have multiple builder producer
         Compilation compilation = compile(
                 "@Document\n"
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
index ce079ea..72edbd2 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
@@ -168,8 +168,8 @@
             if (simplifiedTimingOnlyMode) 0 else BenchmarkState.REPEAT_COUNT_ALLOCATION
         val expectedCount = report.warmupIterations +
             report.repeatIterations * expectedRepeatCount +
-            // method tracing phase by default only when API > 21, and simplified timing off
-            if (simplifiedTimingOnlyMode || Build.VERSION.SDK_INT <= 21) 0 else 1
+            // method tracing phase by default only when API in 22..33, and simplified timing off
+            if (Build.VERSION.SDK_INT in 22..33 && !simplifiedTimingOnlyMode) 1 else 0
         assertEquals(expectedCount, total)
 
         if (Arguments.iterations != null) {
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
index c866e25..d431e05 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
@@ -90,10 +90,11 @@
         val argumentName = "profiling.mode"
         val argumentValue = getBenchmarkArgument(argumentName, "DEFAULT_VAL")
         if (argumentValue == "DEFAULT_VAL") {
-            return if (Build.VERSION.SDK_INT > 21) {
+            return if (Build.VERSION.SDK_INT in 22..33) {
                 MethodTracing to true
             } else {
                 // Method tracing can corrupt the stack on API 21, see b/300658578
+                // on API 34, it causes regressions in jit behavior, see b/303686344
                 null to true
             }
         }
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 9d96b85..aeb7b1b 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
@@ -21,9 +21,11 @@
 import androidx.bluetooth.BluetoothLe
 import java.util.UUID
 import kotlinx.coroutines.cancel
+import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert
+import org.junit.Assert.assertTrue
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.robolectric.RobolectricTestRunner
@@ -46,6 +48,17 @@
         }
     }
 
+    @Test
+    fun advertise_noBlock() = runTest {
+        val params = AdvertiseParams()
+        val advertiseJob = launch {
+            bluetoothLe.advertise(params)
+        }
+        delay(100)
+        assertTrue(advertiseJob.isActive)
+        advertiseJob.cancel()
+    }
+
     /**
      * Tests if [BluetoothLe.advertise] returns error when data is larger than
      * the legacy advertise limit (31 bytes)
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattServerTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattServerTest.kt
index 14f8951..6882a83 100644
--- a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattServerTest.kt
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattServerTest.kt
@@ -42,6 +42,7 @@
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.runTest
 import org.junit.Assert
+import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
@@ -71,8 +72,6 @@
         private val notifyCharUuid = UUID.fromString("00002223-0000-1000-8000-00805F9B34FB")
         private val unknownCharUuid = UUID.fromString("00002224-0000-1000-8000-00805F9B34FB")
 
-        private val cccdUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
-
         private val readCharacteristic = GattCharacteristic(readCharUuid, PROPERTY_READ)
         private val writeCharacteristic = GattCharacteristic(
             writeCharUuid, PROPERTY_READ or PROPERTY_WRITE
@@ -99,6 +98,8 @@
     @Test
     fun openGattServer() = runTest {
         val device = createDevice("00:11:22:33:44:55")
+        val deviceName = "Device A"
+        shadowOf(device).setName(deviceName)
         val opened = CompletableDeferred<Unit>()
         val closed = CompletableDeferred<Unit>()
 
@@ -112,7 +113,10 @@
             }
 
         bluetoothLe.openGattServer(listOf()) {
-            connectRequests.first().accept {}
+            connectRequests.first().let {
+                assertEquals(deviceName, it.device.name)
+                it.accept {}
+            }
         }
 
         assertTrue(opened.isCompleted)
@@ -438,7 +442,7 @@
             bluetoothLe.openGattServer(services) {
                 connectRequests.collect {
                     it.accept {
-                        assertTrue(notify(notifyCharacteristic, valueToNotify.toByteArray()))
+                        notify(notifyCharacteristic, valueToNotify.toByteArray())
                         // Close the server
                         [email protected]()
                     }
@@ -589,10 +593,12 @@
             characteristic: FwkCharacteristic,
             confirm: Boolean,
             value: ByteArray
-        ) {
-            baseAdapter.notifyCharacteristicChanged(device, characteristic, confirm, value)
-            onNotifyCharacteristicChangedListener
-                ?.onNotifyCharacteristicChanged(device, characteristic, confirm, value)
+        ): Int? {
+            baseAdapter.notifyCharacteristicChanged(device, characteristic, confirm, value).let {
+                onNotifyCharacteristicChangedListener
+                    ?.onNotifyCharacteristicChanged(device, characteristic, confirm, value)
+                return it
+            }
         }
 
         override fun sendResponse(
diff --git a/bluetooth/bluetooth/api/current.txt b/bluetooth/bluetooth/api/current.txt
index c7ef8cd..6f3e787 100644
--- a/bluetooth/bluetooth/api/current.txt
+++ b/bluetooth/bluetooth/api/current.txt
@@ -91,7 +91,7 @@
   public static interface BluetoothLe.GattServerSessionScope {
     method public androidx.bluetooth.BluetoothDevice getDevice();
     method public kotlinx.coroutines.flow.Flow<androidx.bluetooth.GattServerRequest> getRequests();
-    method public suspend Object? notify(androidx.bluetooth.GattCharacteristic characteristic, byte[] value, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
+    method public suspend Object? notify(androidx.bluetooth.GattCharacteristic characteristic, byte[] value, kotlin.coroutines.Continuation<? super kotlin.Unit>);
     property public abstract androidx.bluetooth.BluetoothDevice device;
     property public abstract kotlinx.coroutines.flow.Flow<androidx.bluetooth.GattServerRequest> requests;
   }
diff --git a/bluetooth/bluetooth/api/restricted_current.txt b/bluetooth/bluetooth/api/restricted_current.txt
index c7ef8cd..6f3e787 100644
--- a/bluetooth/bluetooth/api/restricted_current.txt
+++ b/bluetooth/bluetooth/api/restricted_current.txt
@@ -91,7 +91,7 @@
   public static interface BluetoothLe.GattServerSessionScope {
     method public androidx.bluetooth.BluetoothDevice getDevice();
     method public kotlinx.coroutines.flow.Flow<androidx.bluetooth.GattServerRequest> getRequests();
-    method public suspend Object? notify(androidx.bluetooth.GattCharacteristic characteristic, byte[] value, kotlin.coroutines.Continuation<? super java.lang.Boolean>);
+    method public suspend Object? notify(androidx.bluetooth.GattCharacteristic characteristic, byte[] value, kotlin.coroutines.Continuation<? super kotlin.Unit>);
     property public abstract androidx.bluetooth.BluetoothDevice device;
     property public abstract kotlinx.coroutines.flow.Flow<androidx.bluetooth.GattServerRequest> requests;
   }
diff --git a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothAddressTest.kt b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothAddressTest.kt
index 3c0e6e4..562d22e 100644
--- a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothAddressTest.kt
+++ b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothAddressTest.kt
@@ -18,6 +18,7 @@
 
 import junit.framework.TestCase.assertEquals
 import kotlin.test.assertFailsWith
+import kotlin.test.assertNotEquals
 import org.junit.Assert.assertTrue
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -80,4 +81,25 @@
             BluetoothAddress(invalidAddress, BluetoothAddress.ADDRESS_TYPE_UNKNOWN)
         }
     }
+
+    @Test
+    fun equality() {
+        val publicAddress = BluetoothAddress(TEST_ADDRESS_PUBLIC,
+            BluetoothAddress.ADDRESS_TYPE_PUBLIC)
+        val sameAddress = BluetoothAddress(TEST_ADDRESS_PUBLIC,
+            BluetoothAddress.ADDRESS_TYPE_PUBLIC)
+        val addressWithDifferentAddress = BluetoothAddress(
+            TEST_ADDRESS_RANDOM_STATIC,
+            BluetoothAddress.ADDRESS_TYPE_PUBLIC
+        )
+        val addressWithDifferentType = BluetoothAddress(
+            TEST_ADDRESS_PUBLIC,
+            BluetoothAddress.ADDRESS_TYPE_RANDOM_STATIC
+        )
+
+        assertEquals(publicAddress, sameAddress)
+        assertEquals(publicAddress.hashCode(), sameAddress.hashCode())
+        assertNotEquals(publicAddress, addressWithDifferentAddress)
+        assertNotEquals(publicAddress, addressWithDifferentType)
+    }
 }
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
index 153959b..17d1437 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
@@ -285,6 +285,9 @@
         /**
          * Writes the characteristic value to the server.
          *
+         * It could fail if the [characteristic] doesn't have the write property or the length
+         * of the [value] is greater than the maximum length of an attribute value (512).
+         *
          * @param characteristic a remote [GattCharacteristic] to write
          * @param value a value to be written.
          * @return the result of the write operation
@@ -372,9 +375,9 @@
          * @param characteristic the updated characteristic
          * @param value the new value of the characteristic
          *
-         * @return `true` if the notification sent successfully, otherwise `false`
+         * @throws CancellationException if it failed to notify
          */
-        suspend fun notify(characteristic: GattCharacteristic, value: ByteArray): Boolean
+        suspend fun notify(characteristic: GattCharacteristic, value: ByteArray)
     }
 
     /**
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt
index bfcfa45..a2e1ce6 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt
@@ -90,10 +90,11 @@
     companion object {
         private const val TAG = "GattClient"
 
+        private const val GATT_MAX_ATTR_LENGTH = 512
         /**
-         * The maximum ATT size(512) + header(3)
+         * The maximum ATT size + header(3)
          */
-        private const val GATT_MAX_MTU = 515
+        private const val GATT_MAX_MTU = GATT_MAX_ATTR_LENGTH + 3
 
         private const val CONNECT_TIMEOUT_MS = 30_000L
         private val CCCD_UID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
@@ -289,9 +290,14 @@
                     else return Result.failure(
                         IllegalArgumentException("can't write to the characteristic"))
 
+                if (value.size > GATT_MAX_ATTR_LENGTH) {
+                    return Result.failure(IllegalArgumentException("too long value to write"))
+                }
+
                 return runTask {
                     fwkAdapter.writeCharacteristic(
-                        characteristic.fwkCharacteristic, value, writeType)
+                        characteristic.fwkCharacteristic, value, writeType
+                    )
                     val res = takeMatchingResult<CallbackResult.OnCharacteristicWrite>(
                         callbackResultsFlow
                     ) {
@@ -299,7 +305,7 @@
                     }
                     if (res.status == BluetoothGatt.GATT_SUCCESS) Result.success(Unit)
                     // TODO: throw precise reason if we can gather the info
-                    else Result.failure(CancellationException("fail"))
+                    else Result.failure(CancellationException("fail with error = ${res.status}"))
                 }
             }
 
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt
index 95a35a7..3d5566a6 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt
@@ -27,11 +27,13 @@
 import android.bluetooth.BluetoothGattService as FwkService
 import android.bluetooth.BluetoothManager
 import android.bluetooth.BluetoothProfile
+import android.bluetooth.BluetoothStatusCodes
 import android.content.Context
 import android.os.Build
 import androidx.annotation.RequiresPermission
 import androidx.annotation.RestrictTo
 import androidx.annotation.VisibleForTesting
+import java.util.concurrent.CancellationException
 import java.util.concurrent.atomic.AtomicBoolean
 import java.util.concurrent.atomic.AtomicInteger
 import kotlinx.coroutines.CompletableDeferred
@@ -58,7 +60,7 @@
             characteristic: FwkCharacteristic,
             confirm: Boolean,
             value: ByteArray
-        )
+        ): Int?
         fun sendResponse(
             device: FwkDevice,
             requestId: Int,
@@ -286,7 +288,7 @@
                         override suspend fun notify(
                             characteristic: GattCharacteristic,
                             value: ByteArray
-                        ): Boolean {
+                        ) {
                             notifyMutex.withLock {
                                 CompletableDeferred<Boolean>().also {
                                     notifyJob = it
@@ -295,8 +297,13 @@
                                         characteristic.fwkCharacteristic,
                                         false,
                                         value
-                                    )
-                                    return it.await()
+                                    ).let { notifyResult ->
+                                        if (notifyResult != BluetoothStatusCodes.SUCCESS) {
+                                            throw CancellationException("notify failed with " +
+                                                "error: {$notifyResult}")
+                                        }
+                                    }
+                                    it.await()
                                 }
                             }
                         }
@@ -361,9 +368,11 @@
             characteristic: FwkCharacteristic,
             confirm: Boolean,
             value: ByteArray
-        ) {
+        ): Int? {
             characteristic.value = value
-            gattServer?.notifyCharacteristicChanged(device, characteristic, confirm)
+            return gattServer?.notifyCharacteristicChanged(device, characteristic, confirm)?.let {
+                if (it) BluetoothStatusCodes.SUCCESS else BluetoothStatusCodes.ERROR_UNKNOWN
+            }
         }
 
         @RequiresPermission(BLUETOOTH_CONNECT)
@@ -385,8 +394,8 @@
             characteristic: FwkCharacteristic,
             confirm: Boolean,
             value: ByteArray
-        ) {
-            gattServer?.notifyCharacteristicChanged(device, characteristic, confirm, value)
+        ): Int? {
+            return gattServer?.notifyCharacteristicChanged(device, characteristic, confirm, value)
         }
     }
 }
diff --git a/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/ChangeInfoGitClientTest.kt b/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/ChangeInfoGitClientTest.kt
index aedf44140..c5c6a59 100644
--- a/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/ChangeInfoGitClientTest.kt
+++ b/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/ChangeInfoGitClientTest.kt
@@ -17,9 +17,7 @@
 package androidx.build.dependencyTracker
 
 import androidx.build.gitclient.ChangeInfoGitClient
-import androidx.build.gitclient.GitCommitRange
 import com.google.gson.JsonSyntaxException
-import java.io.File
 import junit.framework.TestCase.assertEquals
 import org.gradle.api.GradleException
 import org.junit.Test
@@ -234,11 +232,11 @@
             </manifest>
             """,
             "frameworks/support")
-        return client.findChangedFilesSince("", "", false)
+        return client.findChangedFilesSince("")
     }
 
     @Test
-    fun getGitLog_hasVersion() {
+    fun getHeadSha_hasVersion() {
         checkVersion("""
             <manifest>
                 <project path="prebuilts/internal" name="platform/prebuilts/internal" revision="prebuiltsVersion1"/>
@@ -251,7 +249,7 @@
     }
 
     @Test
-    fun getGitLog_noVersion() {
+    fun getHeadSha_noVersion() {
         var threw = false
         try {
             checkVersion("""
@@ -268,9 +266,8 @@
     fun checkVersion(config: String, expectedVersion: String?) {
         assertEquals(expectedVersion, getVersion(config))
     }
-    fun getVersion(config: String): String? {
+    fun getVersion(config: String): String {
         return ChangeInfoGitClient("{}", config, "frameworks/support")
-            .getGitLog(GitCommitRange(n = 1), keepMerges = true, projectDir = File("."))
-            .getOrNull(0)?.sha
+            .getHeadSha()
     }
 }
diff --git a/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/GitRunnerGitClientTest.kt b/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/GitRunnerGitClientTest.kt
index eb24eee..7a5b452 100644
--- a/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/GitRunnerGitClientTest.kt
+++ b/buildSrc-tests/src/test/java/androidx/build/dependencyTracker/GitRunnerGitClientTest.kt
@@ -16,19 +16,18 @@
 
 package androidx.build.dependencyTracker
 
-import androidx.build.gitclient.Commit
 import androidx.build.gitclient.GitClient
 import androidx.build.gitclient.GitRunnerGitClient
 import androidx.build.gitclient.GitRunnerGitClient.Companion.CHANGED_FILES_CMD_PREFIX
 import androidx.build.gitclient.GitRunnerGitClient.Companion.PREVIOUS_SUBMITTED_CMD
-import androidx.build.gitclient.GitCommitRange
+import java.io.File
 import junit.framework.TestCase.assertEquals
+import junit.framework.TestCase.assertFalse
 import junit.framework.TestCase.assertNull
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
-import java.io.File
 
 @RunWith(JUnit4::class)
 class GitRunnerGitClientTest {
@@ -70,12 +69,12 @@
                 convertToFilePath("a", "b", "c.java"),
                 convertToFilePath("d", "e", "f.java"))
         commandRunner.addReply(
-                "$CHANGED_FILES_CMD_PREFIX HEAD..mySha",
+                "$CHANGED_FILES_CMD_PREFIX HEAD mySha",
                 changes.joinToString(System.lineSeparator())
         )
         assertEquals(
                 changes,
-                client.findChangedFilesSince(sha = "mySha", includeUncommitted = true))
+                client.findChangedFilesSince(sha = "mySha"))
     }
 
     @Test
@@ -86,38 +85,9 @@
     }
 
     @Test
-    fun findChangesSince_twoCls() {
-        var changes = listOf(
-                convertToFilePath("a", "b", "c.java"),
-                convertToFilePath("d", "e", "f.java"))
-        commandRunner.addReply(
-                "$CHANGED_FILES_CMD_PREFIX otherSha mySha",
-                changes.joinToString(System.lineSeparator())
-        )
-        assertEquals(
-                changes,
-                client.findChangedFilesSince(
-                        sha = "mySha",
-                        top = "otherSha",
-                        includeUncommitted = false))
-    }
-
-    @Test
     fun checkLatestCommitExists() {
-        /* Do not use the MockCommandRunner because it's a better test to check the validity of
-         * the git command against the actual git in the repo
-         */
-        val commitList: List<Commit> = GitRunnerGitClient(workingDir, logger)
-            .getGitLog(
-                GitCommitRange(
-                    fromExclusive = "",
-                    untilInclusive = "HEAD",
-                    n = 1
-                ),
-                keepMerges = true,
-                projectDir = workingDir
-        )
-        assertEquals(1, commitList.size)
+        val headCommit: String = GitRunnerGitClient(workingDir, logger).getHeadSha()
+        assertFalse(headCommit.isEmpty())
     }
 
     // For both Linux/Windows
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
index 24e34dc..0ee112e 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
@@ -113,6 +113,11 @@
 const val KMP_GITHUB_BUILD = "androidx.github.build"
 
 /**
+ * Specifies to give as much memory to Gradle as in a typical CI run
+ */
+const val HIGH_MEMORY = "androidx.highMemory"
+
+/**
  * If true, don't require lint-checks project to exist. This should only be set in integration
  * tests, to allow them to save time by not configuring extra projects.
  */
@@ -152,6 +157,7 @@
         ENABLE_COMPOSE_COMPILER_REPORTS,
         DISPLAY_TEST_OUTPUT,
         ENABLE_DOCUMENTATION,
+        HIGH_MEMORY,
         STUDIO_TYPE,
         SUMMARIZE_STANDARD_ERROR,
         USE_MAX_DEP_VERSIONS,
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/gitclient/ChangeInfoGitClient.kt b/buildSrc/private/src/main/kotlin/androidx/build/gitclient/ChangeInfoGitClient.kt
index bfb9427..dba8e59 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/gitclient/ChangeInfoGitClient.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/gitclient/ChangeInfoGitClient.kt
@@ -18,7 +18,6 @@
 
 import androidx.build.parseXml
 import com.google.gson.Gson
-import java.io.File
 import org.gradle.api.GradleException
 
 /**
@@ -101,16 +100,8 @@
 
     /** Finds changed file paths */
     override fun findChangedFilesSince(
-        sha: String, // unused in this implementation, the data file knows what is new
-        top: String, // unused in this implementation, the data file knows what is new
-        includeUncommitted: Boolean // unused in this implementation, not needed yet
+        sha: String // unused in this implementation, the data file knows what is new
     ): List<String> {
-        if (includeUncommitted) {
-            throw UnsupportedOperationException(
-                "ChangeInfoGitClient does not support includeUncommitted == true yet"
-            )
-        }
-
         val fileList = mutableListOf<String>()
         val fileSet = mutableSetOf<String>()
         for (change in changesInThisRepo) {
@@ -147,24 +138,8 @@
         return ""
     }
 
-    /** Finds the commits in a certain range */
-    override fun getGitLog(
-        gitCommitRange: GitCommitRange,
-        keepMerges: Boolean,
-        projectDir: File?
-    ): List<Commit> {
-        if (gitCommitRange.n != 1) {
-            throw UnsupportedOperationException(
-                "ChangeInfoGitClient only supports n = 1, not ${gitCommitRange.n}"
-            )
-        }
-        if (gitCommitRange.untilInclusive != "HEAD") {
-            throw UnsupportedOperationException(
-                "ChangeInfoGitClient only supports untilInclusive = HEAD, " +
-                    "not ${gitCommitRange.untilInclusive}"
-            )
-        }
-        return listOf(Commit("_CommitSHA:${extractVersion(versionInfo)}", projectPath))
+    override fun getHeadSha(): String {
+        return extractVersion(versionInfo)
     }
 }
 
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitClient.kt b/buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitClient.kt
index f6d757f..2b883ba 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitClient.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitClient.kt
@@ -17,8 +17,6 @@
 package androidx.build.gitclient
 
 import androidx.build.getCheckoutRoot
-import androidx.build.releasenotes.getBuganizerLink
-import androidx.build.releasenotes.getChangeIdAOSPLink
 import java.io.File
 import java.util.concurrent.ConcurrentHashMap
 import org.gradle.api.GradleException
@@ -27,34 +25,12 @@
 import org.gradle.api.provider.Provider
 
 interface GitClient {
-    fun findChangedFilesSince(
-        sha: String,
-        top: String = "HEAD",
-        includeUncommitted: Boolean = false
-    ): List<String>
+    fun findChangedFilesSince(sha: String): List<String>
 
     fun findPreviousSubmittedChange(): String?
 
-    fun getGitLog(
-        gitCommitRange: GitCommitRange,
-        keepMerges: Boolean,
-        projectDir: File?
-    ): List<Commit>
-
     /** Returns the full commit sha for the HEAD of the git repository */
-    fun getHeadSha(): String {
-        val projectDir = null
-        val commitList: List<Commit> =
-            getGitLog(
-                GitCommitRange(fromExclusive = "", untilInclusive = "HEAD", n = 1),
-                keepMerges = true,
-                projectDir = projectDir
-            )
-        if (commitList.isEmpty()) {
-            throw RuntimeException("Failed to find git commit for HEAD!")
-        }
-        return commitList.first().sha
-    }
+    fun getHeadSha(): String
 
     /** Abstraction for running execution commands for testability */
     interface CommandRunner {
@@ -154,247 +130,3 @@
         }
     }
 }
-
-enum class CommitType {
-    NEW_FEATURE,
-    API_CHANGE,
-    BUG_FIX,
-    EXTERNAL_CONTRIBUTION;
-
-    companion object {
-        fun getTitle(commitType: CommitType): String {
-            return when (commitType) {
-                NEW_FEATURE -> "New Features"
-                API_CHANGE -> "API Changes"
-                BUG_FIX -> "Bug Fixes"
-                EXTERNAL_CONTRIBUTION -> "External Contribution"
-            }
-        }
-    }
-}
-
-/**
- * Defines the parameters for a git log command
- *
- * @property fromExclusive the oldest SHA at which the git log starts. Set to an empty string to use
- *   [n]
- * @property untilInclusive the latest SHA included in the git log. Defaults to HEAD
- * @property n a count of how many commits to go back to. Only used when [fromExclusive] is an empty
- *   string
- */
-data class GitCommitRange(
-    val fromExclusive: String = "",
-    val untilInclusive: String = "HEAD",
-    val n: Int = 0
-)
-
-/**
- * Class implementation of a git commit. It uses the input delimiters to parse the commit
- *
- * @property formattedCommitText a string representation of a git commit
- * @property projectDir the project directory for which to parse file paths from a commit
- * @property commitSHADelimiter the term to use to search for the commit SHA
- * @property subjectDelimiter the term to use to search for the subject (aka commit summary)
- * @property changeIdDelimiter the term to use to search for the change-id in the body of the commit
- *   message
- * @property authorEmailDelimiter the term to use to search for the author email
- */
-data class Commit(
-    val formattedCommitText: String,
-    val projectDir: String,
-    private val commitSHADelimiter: String = "_CommitSHA:",
-    private val subjectDelimiter: String = "_Subject:",
-    private val authorEmailDelimiter: String = "_Author:"
-) {
-    private val changeIdDelimiter: String = "Change-Id:"
-    var bugs: MutableList<Int> = mutableListOf()
-    var files: MutableList<String> = mutableListOf()
-    var sha: String = ""
-    var authorEmail: String = ""
-    var changeId: String = ""
-    var summary: String = ""
-    var type: CommitType = CommitType.BUG_FIX
-    var releaseNote: String = ""
-    private val releaseNoteDelimiters: List<String> = listOf("Relnote:")
-
-    init {
-        val listedCommit: List<String> = formattedCommitText.split('\n')
-        listedCommit
-            .filter { line -> line.trim() != "" }
-            .forEach { line -> processCommitLine(line) }
-    }
-
-    private fun processCommitLine(line: String) {
-        if (commitSHADelimiter in line) {
-            getSHAFromGitLine(line)
-            return
-        }
-        if (subjectDelimiter in line) {
-            getSummary(line)
-            return
-        }
-        if (changeIdDelimiter in line) {
-            getChangeIdFromGitLine(line)
-            return
-        }
-        if (authorEmailDelimiter in line) {
-            getAuthorEmailFromGitLine(line)
-            return
-        }
-        if (
-            "Bug:" in line ||
-                "b/" in line ||
-                "bug:" in line ||
-                "Fixes:" in line ||
-                "fixes b/" in line
-        ) {
-            getBugsFromGitLine(line)
-            return
-        }
-        releaseNoteDelimiters.forEach { delimiter ->
-            if (delimiter in line) {
-                getReleaseNotesFromGitLine(line, formattedCommitText)
-                return
-            }
-        }
-        if (projectDir.trim('/') in line) {
-            getFileFromGitLine(line)
-            return
-        }
-    }
-
-    private fun isExternalAuthorEmail(authorEmail: String): Boolean {
-        return !(authorEmail.contains("@google.com"))
-    }
-
-    /**
-     * Parses SHAs from git commit line, with the format: [Commit.commitSHADelimiter] <commitSHA>
-     */
-    private fun getSHAFromGitLine(line: String) {
-        sha = line.substringAfter(commitSHADelimiter).trim()
-    }
-
-    /**
-     * Parses subject from git commit line, with the format: [Commit.subjectDelimiter]<commit
-     * subject>
-     */
-    private fun getSummary(line: String) {
-        summary = line.substringAfter(subjectDelimiter).trim()
-    }
-
-    /** Parses commit Change-Id lines, with the format: `commit.changeIdDelimiter` <changeId> */
-    private fun getChangeIdFromGitLine(line: String) {
-        changeId = line.substringAfter(changeIdDelimiter).trim()
-    }
-
-    /**
-     * Parses commit author lines, with the format: [Commit.authorEmailDelimiter][email protected]
-     */
-    private fun getAuthorEmailFromGitLine(line: String) {
-        authorEmail = line.substringAfter(authorEmailDelimiter).trim()
-        if (isExternalAuthorEmail(authorEmail)) {
-            type = CommitType.EXTERNAL_CONTRIBUTION
-        }
-    }
-
-    /**
-     * Parses filepath to get changed files from commit, with the format:
-     * {project_directory}/{filepath}
-     */
-    private fun getFileFromGitLine(filepath: String) {
-        files.add(filepath.trim())
-        if (filepath.contains("current.txt") && type != CommitType.EXTERNAL_CONTRIBUTION) {
-            type = CommitType.API_CHANGE
-        }
-    }
-
-    /** Parses bugs from a git commit message line */
-    private fun getBugsFromGitLine(line: String) {
-        var formattedLine = line.replace("b/", " ")
-        formattedLine = formattedLine.replace(":", " ")
-        formattedLine = formattedLine.replace(",", " ")
-        var words: List<String> = formattedLine.split(' ')
-        words.forEach { word ->
-            var possibleBug: Int? = word.toIntOrNull()
-            if (possibleBug != null && possibleBug > 1000) {
-                bugs.add(possibleBug)
-            }
-        }
-    }
-
-    /**
-     * Reads in the release notes field from the git commit message line
-     *
-     * They can have a couple valid formats:
-     *
-     * `Release notes: This is a one-line release note` `Release Notes: "This is a multi-line
-     * release note. This accounts for the use case where the commit cannot be explained in one
-     * line" `release notes: "This is a one-line release note. The quotes can be used this way too"`
-     */
-    private fun getReleaseNotesFromGitLine(line: String, formattedCommitText: String) {
-        /* Account for the use of quotes in a release note line
-         * No quotes in the Release Note line means it's a one-line release note
-         * If there are quotes, assume it's a multi-line release note
-         */
-        var quoteCountInRelNoteLine: Int = 0
-        line.forEach { character ->
-            if (character == '"') {
-                quoteCountInRelNoteLine++
-            }
-        }
-        if (quoteCountInRelNoteLine == 0) {
-            getOneLineReleaseNotesFromGitLine(line)
-        } else {
-            releaseNoteDelimiters.forEach { delimiter ->
-                if (delimiter in line) {
-                    // Find the starting quote of the release notes quote block
-                    var releaseNoteStartIndex = formattedCommitText.lastIndexOf(delimiter)
-                    +delimiter.length
-                    releaseNoteStartIndex = formattedCommitText.indexOf('"', releaseNoteStartIndex)
-                    // Move to the character after the first quote
-                    if (formattedCommitText[releaseNoteStartIndex] == '"') {
-                        releaseNoteStartIndex++
-                    }
-                    // Find the ending quote of the release notes quote block
-                    var releaseNoteEndIndex = releaseNoteStartIndex + 1
-                    releaseNoteEndIndex = formattedCommitText.indexOf('"', releaseNoteEndIndex)
-                    // If there is no closing quote, just use the first line
-                    if (releaseNoteEndIndex < 0) {
-                        getOneLineReleaseNotesFromGitLine(line)
-                        return
-                    }
-                    releaseNote =
-                        formattedCommitText
-                            .substring(
-                                startIndex = releaseNoteStartIndex,
-                                endIndex = releaseNoteEndIndex
-                            )
-                            .trim()
-                }
-            }
-        }
-    }
-
-    private fun getOneLineReleaseNotesFromGitLine(line: String) {
-        releaseNoteDelimiters.forEach { delimiter ->
-            if (delimiter in line) {
-                releaseNote = line.substringAfter(delimiter).trim(' ', '"')
-                return
-            }
-        }
-    }
-
-    fun getReleaseNoteString(): String {
-        var releaseNoteString: String = releaseNote
-        releaseNoteString += " ${getChangeIdAOSPLink(changeId)}"
-        bugs.forEach { bug -> releaseNoteString += " ${getBuganizerLink(bug)}" }
-        return releaseNoteString
-    }
-
-    override fun toString(): String {
-        var commitString: String = summary
-        commitString += " ${getChangeIdAOSPLink(changeId)}"
-        bugs.forEach { bug -> commitString += " ${getBuganizerLink(bug)}" }
-        return commitString
-    }
-}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitRunnerGitClient.kt b/buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitRunnerGitClient.kt
index abb6a77..85b929d 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitRunnerGitClient.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/gitclient/GitRunnerGitClient.kt
@@ -32,22 +32,9 @@
         RealCommandRunner(workingDir = workingDir, logger = logger)
 ) : GitClient {
 
-    private val gitRoot: File = findGitDirInParentFilepath(workingDir) ?: workingDir
-
-    /** Finds changed file paths since the given sha */
-    override fun findChangedFilesSince(
-        sha: String,
-        top: String,
-        includeUncommitted: Boolean
-    ): List<String> {
-        // use this if we don't want local changes
-        return commandRunner.executeAndParse(
-            if (includeUncommitted) {
-                "$CHANGED_FILES_CMD_PREFIX HEAD..$sha"
-            } else {
-                "$CHANGED_FILES_CMD_PREFIX $top $sha"
-            }
-        )
+    /** Finds file paths changed in a commit since the given sha */
+    override fun findChangedFilesSince(sha: String): List<String> {
+        return commandRunner.executeAndParse("$CHANGED_FILES_CMD_PREFIX HEAD $sha")
     }
 
     /** checks the history to find the first merge CL. */
@@ -59,99 +46,15 @@
             ?.firstOrNull()
     }
 
-    private fun parseCommitLogString(
-        commitLogString: String,
-        commitStartDelimiter: String,
-        commitSHADelimiter: String,
-        subjectDelimiter: String,
-        authorEmailDelimiter: String,
-        localProjectDir: String
-    ): List<Commit> {
-        // Split commits string out into individual commits (note: this removes the deliminter)
-        val gitLogStringList: List<String>? = commitLogString.split(commitStartDelimiter)
-        var commitLog: MutableList<Commit> = mutableListOf()
-        gitLogStringList
-            ?.filter { gitCommit -> gitCommit.trim() != "" }
-            ?.forEach { gitCommit ->
-                commitLog.add(
-                    Commit(
-                        gitCommit,
-                        localProjectDir,
-                        commitSHADelimiter = commitSHADelimiter,
-                        subjectDelimiter = subjectDelimiter,
-                        authorEmailDelimiter = authorEmailDelimiter
-                    )
-                )
-            }
-        return commitLog.toList()
-    }
-
-    /**
-     * Converts a diff log command into a [List<Commit>]
-     *
-     * @param gitCommitRange the [GitCommitRange] that defines the parameters of the git log command
-     * @param keepMerges boolean for whether or not to add merges to the return [List<Commit>].
-     * @param projectDir a [File] object that represents the project directory.
-     */
-    override fun getGitLog(
-        gitCommitRange: GitCommitRange,
-        keepMerges: Boolean,
-        projectDir: File?
-    ): List<Commit> {
-        val commitStartDelimiter: String = "_CommitStart"
-        val commitSHADelimiter: String = "_CommitSHA:"
-        val subjectDelimiter: String = "_Subject:"
-        val authorEmailDelimiter: String = "_Author:"
-        val dateDelimiter: String = "_Date:"
-        val bodyDelimiter: String = "_Body:"
-        val fullProjectDir = if (projectDir == null) workingDir else projectDir
-        val localProjectDir: String = fullProjectDir.relativeTo(gitRoot).toString()
-        val relativeProjectDir: String = fullProjectDir.relativeTo(workingDir).toString()
-
-        var gitLogOptions: String =
-            "--pretty=format:$commitStartDelimiter%n" +
-                "$commitSHADelimiter%H%n" +
-                "$authorEmailDelimiter%ae%n" +
-                "$dateDelimiter%ad%n" +
-                "$subjectDelimiter%s%n" +
-                "$bodyDelimiter%b" +
-                if (!keepMerges) {
-                    " --no-merges"
-                } else {
-                    ""
-                }
-        var gitLogCmd: String
-        if (gitCommitRange.fromExclusive != "") {
-            gitLogCmd =
-                "$GIT_LOG_CMD_PREFIX $gitLogOptions " +
-                    "${gitCommitRange.fromExclusive}..${gitCommitRange.untilInclusive}" +
-                    " -- ./$relativeProjectDir"
-        } else {
-            gitLogCmd =
-                "$GIT_LOG_CMD_PREFIX $gitLogOptions ${gitCommitRange.untilInclusive} -n " +
-                    "${gitCommitRange.n} -- ./$relativeProjectDir"
-        }
+    override fun getHeadSha(): String {
+        val gitLogCmd = "git log --name-only --pretty=format:%H HEAD -n 1 -- ./"
         val gitLogString: String = commandRunner.execute(gitLogCmd)
-        val commits =
-            parseCommitLogString(
-                gitLogString,
-                commitStartDelimiter,
-                commitSHADelimiter,
-                subjectDelimiter,
-                authorEmailDelimiter,
-                localProjectDir
-            )
-        if (commits.isEmpty()) {
-            // Probably an error; log this
+        if (gitLogString.isEmpty()) {
             logger?.warn(
-                "No git commits found! Ran this command: '" +
-                    gitLogCmd +
-                    "' and received this output: '" +
-                    gitLogString +
-                    "'"
+                "No git commits found! Ran this command: '$gitLogCmd ' and received no output"
             )
         }
-        return commits
+        return gitLogString
     }
 
     private class RealCommandRunner(private val workingDir: File, private val logger: Logger?) :
@@ -181,15 +84,13 @@
         }
 
         override fun executeAndParse(command: String): List<String> {
-            val response = execute(command).split(System.lineSeparator()).filterNot { it.isEmpty() }
-            return response
+            return execute(command).split(System.lineSeparator()).filterNot { it.isEmpty() }
         }
     }
 
     companion object {
         const val PREVIOUS_SUBMITTED_CMD = "git log -1 --merges --oneline"
         const val CHANGED_FILES_CMD_PREFIX = "git diff --name-only"
-        const val GIT_LOG_CMD_PREFIX = "git log --name-only"
     }
 }
 
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/releasenotes/Markdown.kt b/buildSrc/private/src/main/kotlin/androidx/build/releasenotes/Markdown.kt
deleted file mode 100644
index b1f3e6f0..0000000
--- a/buildSrc/private/src/main/kotlin/androidx/build/releasenotes/Markdown.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2019 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.build.releasenotes
-
-/** Classes for generating markdown */
-enum class HeaderType {
-    H1,
-    H2,
-    H3,
-    H4,
-    H5,
-    H6;
-
-    companion object {
-        fun getHeaderTag(tag: HeaderType): String {
-            when (tag) {
-                H1 -> return ("#")
-                H2 -> return ("##")
-                H3 -> return ("###")
-                H4 -> return ("####")
-                H5 -> return ("#####")
-                H6 -> return ("######")
-            }
-        }
-    }
-}
-
-open class MarkdownHeader {
-    var markdownType: HeaderType = HeaderType.H1
-    var text: String = ""
-
-    @Override
-    override fun toString(): String {
-        return HeaderType.getHeaderTag(markdownType) + ' ' + text
-    }
-
-    fun print() {
-        println(toString())
-    }
-}
-
-open class MarkdownLink {
-    var linkText: String = ""
-    var linkUrl: String = ""
-
-    @Override
-    override fun toString(): String {
-        return "([$linkText]($linkUrl))"
-    }
-
-    fun print() {
-        println(toString())
-    }
-}
-
-open class MarkdownBoldText(inputText: String) {
-    var text: String = ""
-
-    init {
-        text = inputText
-    }
-
-    override fun toString(): String {
-        return "**$text**"
-    }
-
-    fun print() {
-        println(toString())
-    }
-}
-
-open class MarkdownComment(inputText: String) {
-    var text: String = ""
-
-    init {
-        text = inputText
-    }
-
-    override fun toString(): String {
-        return "{# $text #}"
-    }
-
-    fun print() {
-        println(toString())
-    }
-}
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/releasenotes/ReleaseNoteMarkdown.kt b/buildSrc/private/src/main/kotlin/androidx/build/releasenotes/ReleaseNoteMarkdown.kt
deleted file mode 100644
index ce85adf..0000000
--- a/buildSrc/private/src/main/kotlin/androidx/build/releasenotes/ReleaseNoteMarkdown.kt
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2019 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.build.releasenotes
-
-import androidx.build.gitclient.Commit
-import androidx.build.gitclient.CommitType
-import java.time.LocalDate
-import java.time.format.DateTimeFormatter
-
-/** Classes for generating androidx release note specific markdown */
-
-/**
- * Markdown class for a Library Header in the format:
- *
- * ### Version <version> {:#<version>}
- */
-class LibraryHeader(groupId: String, version: String) : MarkdownHeader() {
-    init {
-        markdownType = HeaderType.H3
-        text = "$groupId Version $version {:#$version}"
-    }
-}
-
-/**
- * Generates the markdown list of commits with sections defined by enum [CommitType], in the format:
- *
- * **New Features**
- * - <[Commit.summary]> <[getChangeIdAOSPLink]> <[getBuganizerLink] 1> <[getBuganizerLink] 2>...
- *
- * **API Changes**
- * - <[Commit.summary]> <[getChangeIdAOSPLink]> <[getBuganizerLink] 1> <[getBuganizerLink] 2>...
- *
- * **Bug Fixes**
- * - <[Commit.summary]> <[getChangeIdAOSPLink]> <[getBuganizerLink] 1> <[getBuganizerLink] 2>...
- *
- * **External Contribution**
- * - <[Commit.summary]> <[getChangeIdAOSPLink]> <[getBuganizerLink] 1> <[getBuganizerLink] 2>...
- */
-class CommitMarkdownList(private var includeAllCommits: Boolean = false) {
-    private var commits: MutableList<Commit> = mutableListOf()
-
-    fun add(commit: Commit) {
-        commits.add(commit)
-    }
-
-    fun getListItemStr(): String {
-        return "- "
-    }
-
-    private fun makeReleaseNotesSection(sectionCommitType: CommitType): String {
-        var sectionHeader: MarkdownBoldText =
-            MarkdownBoldText(CommitType.getTitle(sectionCommitType))
-        var markdownStringSection: String = ""
-        commits
-            .filter { commit -> commit.type == sectionCommitType }
-            .forEach { commit ->
-                // While we are choosing to ignore Release Note field
-                val commitString: String =
-                    getListItemStr() +
-                        if (commit.releaseNote.isNotEmpty()) commit.getReleaseNoteString()
-                        else commit.toString()
-                if (includeAllCommits || commit.releaseNote.isNotEmpty()) {
-                    markdownStringSection = markdownStringSection + commitString
-                    if (markdownStringSection.last() != '\n') {
-                        markdownStringSection += '\n'
-                    }
-                }
-                /* If we are not ignoring Release Note fields (meaning we are respecting it) and
-                 * the commit does not contain a Release Note field, then don't include the commit
-                 * in the release notes.
-                 */
-            }
-        markdownStringSection =
-            if (markdownStringSection.isEmpty()) {
-                "\n${MarkdownComment(sectionHeader.toString())}\n\n$markdownStringSection"
-            } else {
-                "\n$sectionHeader\n\n$markdownStringSection"
-            }
-        return markdownStringSection
-    }
-
-    @Override
-    override fun toString(): String {
-        var markdownString: String = ""
-        CommitType.values().forEach { commitType ->
-            markdownString += makeReleaseNotesSection(commitType)
-        }
-        return markdownString
-    }
-
-    fun print() {
-        println(toString())
-    }
-}
-
-/**
- * @param startSHA the SHA at which to start the diff log (exclusive)
- * @param endSHA the last SHA to include in the diff log (inclusive)
- * @param projectDir the local directory of the project, in relation to frameworks/support
- * @return A [MarkdownLink] to the public Gitiles diff log
- */
-fun getGitilesDiffLogLink(startSHA: String, endSHA: String, projectDir: String): MarkdownLink {
-    val baseGitilesUrl: String =
-        "https://android.googlesource.com/platform/frameworks/support/+log/"
-    /* The root project directory is already existent in the url path, so the directory here
-     * should be relative to frameworks/support/.
-     */
-    if (projectDir.contains("frameworks/support")) {
-        throw RuntimeException(
-            "Gitiles directory should only contain the directory structure" +
-                "within frameworks/support/*, but received incorrect directory: $projectDir"
-        )
-    }
-    // Remove extra preceeding directory slashes, if they exist
-    var verifiedProjectDir = projectDir
-    while (verifiedProjectDir.first() == '/') {
-        verifiedProjectDir = verifiedProjectDir.removePrefix("/")
-    }
-    var gitilesLink: MarkdownLink = MarkdownLink()
-    gitilesLink.linkText = "here"
-    gitilesLink.linkUrl = "$baseGitilesUrl$startSHA..$endSHA/$verifiedProjectDir"
-    return gitilesLink
-}
-
-/**
- * @param changeId The Gerrit Change-Id to link to
- * @return A [MarkdownLink] to AOSP Gerrit
- */
-fun getChangeIdAOSPLink(changeId: String): MarkdownLink {
-    val baseAOSPUrl: String = "https://android-review.googlesource.com/#/q/"
-    var aospLink: MarkdownLink = MarkdownLink()
-    aospLink.linkText = changeId.take(6)
-    aospLink.linkUrl = "$baseAOSPUrl$changeId"
-    return aospLink
-}
-
-/**
- * @param bugId the Id of the buganizer issue
- * @return A [MarkdownLink] to the public buganizer issue tracker
- *
- * Note: This method does not check if the bug is public
- */
-fun getBuganizerLink(bugId: Int): MarkdownLink {
-    val baseBuganizerUrl: String = "https://issuetracker.google.com/issues/"
-    var buganizerLink: MarkdownLink = MarkdownLink()
-    buganizerLink.linkText = "b/$bugId"
-    buganizerLink.linkUrl = "$baseBuganizerUrl$bugId"
-    return buganizerLink
-}
-
-/**
- * Data class to contain an array of LibraryReleaseNotes when serializing collections of release
- * notes
- */
-data class LibraryReleaseNotesList(val list: MutableList<LibraryReleaseNotes> = mutableListOf())
-
-/**
- * Structured release notes class, that connects all parts of the release notes. Create release
- * notes in the format:
- * <pre>
- * <[LibraryHeader]>
- * <Date>
- *
- * `androidx.<groupId>:<artifactId>:<version>` is released.  The commits included in this version
- * can be found <[MarkdownLink]>.
- *
- *  <[CommitMarkdownList]>
- * </pre>
- *
- * @param includeAllCommits Set to true to include all commits, both with and without a release note
- *   field in the commit message. Defaults to false, which means only commits with a release note
- *   field are included in the release notes.
- * @property groupId Library GroupId.
- * @property artifactIds List of ArtifactIds included in these release notes.
- * @property version Version of the library, assuming all artifactIds have the same version.
- * @property releaseDate Date the release will go live. Defaults to the current date.
- * @property fromSHA The oldest SHA to include in the release notes.
- * @property untilSHA The newest SHA to be included in the release notes.
- * @property projectDir The filepath relative to the parent directory of the .git directory.
- * @property commitList The initial list of Commits to include in these release notes. Defaults to
- *   an empty list. Users can always add more commits with [LibraryReleaseNotes.addCommit]
- * @property requiresSameVersion True if the groupId of this module requires the same version for
- *   all artifactIds in the groupId. When true, uses the GroupId for the release notes header. When
- *   false, uses the list of artifactIds for the header.
- */
-class LibraryReleaseNotes(
-    val groupId: String,
-    val artifactIds: MutableList<String>,
-    val version: String,
-    val releaseDate: LocalDate,
-    val fromSHA: String,
-    val untilSHA: String,
-    val projectDir: String,
-    val commitList: List<Commit> = listOf(),
-    val requiresSameVersion: Boolean,
-    includeAllCommits: Boolean = false
-) {
-    private var diffLogLink: MarkdownLink
-    private var header: LibraryHeader
-    private var commits: MutableList<Commit> = mutableListOf()
-    private var commitMarkdownList: CommitMarkdownList = CommitMarkdownList(includeAllCommits)
-    private var summary: String = ""
-    private var bugsFixed: MutableList<Int> = mutableListOf()
-
-    init {
-        if (version == "" || groupId == "") {
-            throw RuntimeException(
-                "Tried to create Library Release Notes Header without setting" +
-                    "the groupId or version!"
-            )
-        }
-        if (fromSHA == "" || untilSHA == "") {
-            throw RuntimeException("Tried to create Library Release Notes with an empty SHA!")
-        }
-        header =
-            if (requiresSameVersion) {
-                LibraryHeader(groupId, version)
-            } else {
-                LibraryHeader(artifactIds.joinToString(), version)
-            }
-        diffLogLink = getGitilesDiffLogLink(fromSHA, untilSHA, projectDir)
-        if (commitList.isNotEmpty()) {
-            commitList.forEach { commit -> addCommit(commit) }
-        }
-    }
-
-    fun getFormattedDate(): String {
-        val formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy")
-        return formatter.format(releaseDate)
-    }
-
-    fun getFormattedReleaseSummary(): String {
-        val numberArtifacts = artifactIds.size
-        for (i: Int in 0..(numberArtifacts - 1)) {
-            var currentArtifactId: String = artifactIds[i]
-            when (numberArtifacts) {
-                1 -> {
-                    summary = "`$groupId:$currentArtifactId:$version` is released.  "
-                }
-                2 -> {
-                    if (i == 0) {
-                        summary = "`$groupId:$currentArtifactId:$version` and "
-                    }
-                    if (i == 1) {
-                        summary += "`$groupId:$currentArtifactId:$version` are released. "
-                    }
-                }
-                else -> {
-                    if (i < numberArtifacts - 1) {
-                        summary += "`$groupId:$currentArtifactId:$version`, "
-                    } else {
-                        summary += "and `$groupId:$currentArtifactId:$version` are released. "
-                    }
-                }
-            }
-        }
-
-        summary += "The commits included in this version can be found $diffLogLink.\n"
-        return summary
-    }
-
-    fun addCommit(newCommit: Commit) {
-        newCommit.bugs.forEach { bug -> bugsFixed.add(bug) }
-        commits.add(newCommit)
-        commitMarkdownList.add(newCommit)
-    }
-
-    override fun toString(): String {
-        return "$header\n" +
-            "${getFormattedDate()}\n\n" +
-            getFormattedReleaseSummary() +
-            "$commitMarkdownList"
-    }
-}
diff --git a/busytown/androidx_with_metalava.sh b/busytown/androidx_with_metalava.sh
index 156fc64..5084b28 100755
--- a/busytown/androidx_with_metalava.sh
+++ b/busytown/androidx_with_metalava.sh
@@ -2,6 +2,13 @@
 set -e
 SCRIPT_PATH="$(cd $(dirname $0) && pwd)"
 
+# Use this flag to temporarily disable `checkApi`
+# while landing Metalava w/ breaking API changes
+DURING_METALAVA_UPDATE=true
+
+if [ ! $DURING_METALAVA_UPDATE ]
+then
 $SCRIPT_PATH/impl/build-metalava-and-androidx.sh \
   listTaskOutputs \
   checkApi
+fi
diff --git a/busytown/impl/build-metalava-and-androidx.sh b/busytown/impl/build-metalava-and-androidx.sh
index c2652ba..597edf1 100755
--- a/busytown/impl/build-metalava-and-androidx.sh
+++ b/busytown/impl/build-metalava-and-androidx.sh
@@ -44,6 +44,9 @@
 
 buildMetalava
 
+# allow androidx build to reach the network for any new metalava dependencies
+export ALLOW_PUBLIC_REPOS=true
+
 # Mac grep doesn't support -P, so use perl version of `grep -oP "(?<=metalavaVersion=).*"`
 METALAVA_VERSION_FILE="$METALAVA_DIR/version.properties"
 export METALAVA_VERSION=`perl -nle'print $& while m{(?<=metalavaVersion=).*}g' $METALAVA_VERSION_FILE`
diff --git a/busytown/impl/build-studio-and-androidx.sh b/busytown/impl/build-studio-and-androidx.sh
index 6f97a00..ceb9186 100755
--- a/busytown/impl/build-studio-and-androidx.sh
+++ b/busytown/impl/build-studio-and-androidx.sh
@@ -27,6 +27,12 @@
 mkdir -p "$DIST_DIR"
 
 export DIST_DIR="$DIST_DIR"
+if [ "$CHANGE_INFO" != "" ]; then
+  cp "$CHANGE_INFO" "$DIST_DIR/"
+fi
+if [ "$MANIFEST" == "" ]; then
+  export MANIFEST="$DIST_DIR/manifest_${BUILD_NUMBER}.xml"
+fi
 
 # resolve GRADLE_USER_HOME
 export GRADLE_USER_HOME="$OUT_DIR/gradle"
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/Exif.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/Exif.java
index b26e75f..729fa09 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/Exif.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/utils/Exif.java
@@ -50,6 +50,9 @@
 
     /** Timestamp value indicating a timestamp value that is either not set or not valid */
     public static final long INVALID_TIMESTAMP = -1;
+    // Forked from ExifInterface.TAG_THUMBNAIL_ORIENTATION. The value is library-internal so we
+    // can't depend on it directly.
+    public static final String TAG_THUMBNAIL_ORIENTATION = "ThumbnailOrientation";
 
     private static final String TAG = Exif.class.getSimpleName();
 
@@ -94,7 +97,7 @@
             ExifInterface.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
             ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH,
             ExifInterface.TAG_THUMBNAIL_IMAGE_WIDTH,
-            ExifInterface.TAG_THUMBNAIL_ORIENTATION);
+            TAG_THUMBNAIL_ORIENTATION);
 
     private final ExifInterface mExifInterface;
 
@@ -863,7 +866,7 @@
                 ExifInterface.TAG_INTEROPERABILITY_INDEX,
                 ExifInterface.TAG_THUMBNAIL_IMAGE_LENGTH,
                 ExifInterface.TAG_THUMBNAIL_IMAGE_WIDTH,
-                ExifInterface.TAG_THUMBNAIL_ORIENTATION,
+                TAG_THUMBNAIL_ORIENTATION,
                 ExifInterface.TAG_DNG_VERSION,
                 ExifInterface.TAG_DEFAULT_CROP_SIZE,
                 ExifInterface.TAG_ORF_THUMBNAIL_IMAGE,
diff --git a/collection/collection/src/commonMain/kotlin/androidx/collection/PackingUtils.kt b/collection/collection/src/commonMain/kotlin/androidx/collection/PackingUtils.kt
index 00d1b22..48b8171 100644
--- a/collection/collection/src/commonMain/kotlin/androidx/collection/PackingUtils.kt
+++ b/collection/collection/src/commonMain/kotlin/androidx/collection/PackingUtils.kt
@@ -21,8 +21,8 @@
  * Packs two Float values into one Long value for use in inline classes.
  */
 internal inline fun packFloats(val1: Float, val2: Float): Long {
-    val v1 = val1.toBits().toLong()
-    val v2 = val2.toBits().toLong()
+    val v1 = val1.toRawBits().toLong()
+    val v2 = val2.toRawBits().toLong()
     return (v1 shl 32) or (v2 and 0xFFFFFFFF)
 }
 
diff --git a/compose/animation/animation-core/api/current.txt b/compose/animation/animation-core/api/current.txt
index bb16d4a..a3b72cd 100644
--- a/compose/animation/animation-core/api/current.txt
+++ b/compose/animation/animation-core/api/current.txt
@@ -438,6 +438,9 @@
   @SuppressCompatibility @kotlin.RequiresOptIn(message="This API is internal to library.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER}) public @interface InternalAnimationApi {
   }
 
+  public abstract sealed class KeyframeBaseEntity<T> {
+  }
+
   @androidx.compose.runtime.Immutable public final class KeyframesSpec<T> implements androidx.compose.animation.core.DurationBasedAnimationSpec<T> {
     ctor public KeyframesSpec(androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T> config);
     method public androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T> getConfig();
@@ -445,18 +448,22 @@
     property public final androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T> config;
   }
 
-  public static final class KeyframesSpec.KeyframeEntity<T> {
+  public static final class KeyframesSpec.KeyframeEntity<T> extends androidx.compose.animation.core.KeyframeBaseEntity<T> {
   }
 
-  public static final class KeyframesSpec.KeyframesSpecConfig<T> {
+  public static final class KeyframesSpec.KeyframesSpecConfig<T> extends androidx.compose.animation.core.KeyframesSpecBaseConfig<T,androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>> {
     ctor public KeyframesSpec.KeyframesSpecConfig();
-    method public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> at(T, @IntRange(from=0L) int timeStamp);
-    method public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> atFraction(T, float fraction);
-    method @IntRange(from=0L) public int getDelayMillis();
-    method @IntRange(from=0L) public int getDurationMillis();
-    method public void setDelayMillis(int);
-    method public void setDurationMillis(int);
-    method public infix void with(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, androidx.compose.animation.core.Easing easing);
+    method @Deprecated public infix void with(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, androidx.compose.animation.core.Easing easing);
+  }
+
+  public abstract sealed class KeyframesSpecBaseConfig<T, E extends androidx.compose.animation.core.KeyframeBaseEntity<T>> {
+    method public final infix E at(T, @IntRange(from=0L) int timeStamp);
+    method public final infix E atFraction(T, float fraction);
+    method @IntRange(from=0L) public final int getDelayMillis();
+    method @IntRange(from=0L) public final int getDurationMillis();
+    method public final void setDelayMillis(int);
+    method public final void setDurationMillis(int);
+    method public final infix E using(E, androidx.compose.animation.core.Easing easing);
     property @IntRange(from=0L) public final int delayMillis;
     property @IntRange(from=0L) public final int durationMillis;
   }
diff --git a/compose/animation/animation-core/api/restricted_current.txt b/compose/animation/animation-core/api/restricted_current.txt
index b454084..aed261f 100644
--- a/compose/animation/animation-core/api/restricted_current.txt
+++ b/compose/animation/animation-core/api/restricted_current.txt
@@ -438,6 +438,9 @@
   @SuppressCompatibility @kotlin.RequiresOptIn(message="This API is internal to library.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER}) public @interface InternalAnimationApi {
   }
 
+  public abstract sealed class KeyframeBaseEntity<T> {
+  }
+
   @androidx.compose.runtime.Immutable public final class KeyframesSpec<T> implements androidx.compose.animation.core.DurationBasedAnimationSpec<T> {
     ctor public KeyframesSpec(androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T> config);
     method public androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T> getConfig();
@@ -445,18 +448,22 @@
     property public final androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig<T> config;
   }
 
-  public static final class KeyframesSpec.KeyframeEntity<T> {
+  public static final class KeyframesSpec.KeyframeEntity<T> extends androidx.compose.animation.core.KeyframeBaseEntity<T> {
   }
 
-  public static final class KeyframesSpec.KeyframesSpecConfig<T> {
+  public static final class KeyframesSpec.KeyframesSpecConfig<T> extends androidx.compose.animation.core.KeyframesSpecBaseConfig<T,androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>> {
     ctor public KeyframesSpec.KeyframesSpecConfig();
-    method public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> at(T, @IntRange(from=0L) int timeStamp);
-    method public infix androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T> atFraction(T, float fraction);
-    method @IntRange(from=0L) public int getDelayMillis();
-    method @IntRange(from=0L) public int getDurationMillis();
-    method public void setDelayMillis(int);
-    method public void setDurationMillis(int);
-    method public infix void with(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, androidx.compose.animation.core.Easing easing);
+    method @Deprecated public infix void with(androidx.compose.animation.core.KeyframesSpec.KeyframeEntity<T>, androidx.compose.animation.core.Easing easing);
+  }
+
+  public abstract sealed class KeyframesSpecBaseConfig<T, E extends androidx.compose.animation.core.KeyframeBaseEntity<T>> {
+    method public final infix E at(T, @IntRange(from=0L) int timeStamp);
+    method public final infix E atFraction(T, float fraction);
+    method @IntRange(from=0L) public final int getDelayMillis();
+    method @IntRange(from=0L) public final int getDurationMillis();
+    method public final void setDelayMillis(int);
+    method public final void setDurationMillis(int);
+    method public final infix E using(E, androidx.compose.animation.core.Easing easing);
     property @IntRange(from=0L) public final int delayMillis;
     property @IntRange(from=0L) public final int durationMillis;
   }
diff --git a/compose/animation/animation-core/build.gradle b/compose/animation/animation-core/build.gradle
index 09f7c49..7c19839 100644
--- a/compose/animation/animation-core/build.gradle
+++ b/compose/animation/animation-core/build.gradle
@@ -40,6 +40,7 @@
                 implementation(project(":compose:ui:ui"))
                 implementation(project(":compose:ui:ui-unit"))
                 implementation(project(":compose:ui:ui-util"))
+                implementation(project(":collection:collection"))
                 implementation(libs.kotlinStdlibCommon)
                 api(libs.kotlinCoroutinesCore)
             }
diff --git a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/InfiniteTransitionSamples.kt b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/InfiniteTransitionSamples.kt
index 1977ca9..4973e4f 100644
--- a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/InfiniteTransitionSamples.kt
+++ b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/InfiniteTransitionSamples.kt
@@ -109,7 +109,7 @@
             animation = keyframes {
                 durationMillis = 500
                 0.dp at 200 // ms
-                80.dp at 300 with FastOutLinearInEasing
+                80.dp at 300 using FastOutLinearInEasing
             }
             // Use the default RepeatMode.Restart to start from 0.dp after each iteration
         )
diff --git a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt
index 6839179..b461a6e 100644
--- a/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt
+++ b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt
@@ -19,6 +19,7 @@
 import androidx.annotation.Sampled
 import androidx.compose.animation.core.FastOutSlowInEasing
 import androidx.compose.animation.core.KeyframesSpec
+import androidx.compose.animation.core.KeyframesSpecBaseConfig
 import androidx.compose.animation.core.LinearEasing
 import androidx.compose.animation.core.LinearOutSlowInEasing
 import androidx.compose.animation.core.keyframes
@@ -55,8 +56,8 @@
     // time between 50 and 100ms
     keyframes<Float> {
         durationMillis = 100
-        0f at 0 with FastOutSlowInEasing
-        1.5f at 50 with LinearOutSlowInEasing
+        0f at 0 using FastOutSlowInEasing
+        1.5f at 50 using LinearOutSlowInEasing
         1f at 100
     }
 }
@@ -67,8 +68,21 @@
     // time between 50 and 100ms
     keyframes<DpOffset> {
         durationMillis = 200
-        DpOffset(0.dp, 0.dp) at 0 with LinearEasing
-        DpOffset(500.dp, 100.dp) at 100 with LinearOutSlowInEasing
+        DpOffset(0.dp, 0.dp) at 0 using LinearEasing
+        DpOffset(500.dp, 100.dp) at 100 using LinearOutSlowInEasing
         DpOffset(400.dp, 50.dp) at 150
     }
 }
+
+@Sampled
+fun KeyframesSpecBaseConfig<Float, KeyframesSpec.KeyframeEntity<Float>>.floatAtSample() {
+    0.8f at 150 // ms
+}
+
+@Sampled
+fun KeyframesSpecBaseConfig<Float, KeyframesSpec.KeyframeEntity<Float>>.floatAtFractionSample() {
+    // Make sure to set the duration before calling `atFraction` otherwise the keyframe will be set
+    // based on the default duration
+    durationMillis = 300
+    0.8f atFraction 0.50f // half of the overall duration set
+}
diff --git a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/KeyframeAnimationTest.kt b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/KeyframeAnimationTest.kt
index dc1a67a..072294a 100644
--- a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/KeyframeAnimationTest.kt
+++ b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/KeyframeAnimationTest.kt
@@ -78,7 +78,7 @@
         val easing = FastOutSlowInEasing
         val animation = keyframes<Float> {
             durationMillis = 100
-            0f at 0 with easing
+            0f at 0 using easing
             1f at durationMillis
         }.vectorize(Float.VectorConverter)
 
@@ -90,7 +90,7 @@
         val easing = FastOutSlowInEasing
         val animation = keyframes<Float> {
             durationMillis = 200
-            1f at 100 with easing
+            1f at 100 using easing
             2f at durationMillis
         }.vectorize(Float.VectorConverter)
 
@@ -101,7 +101,7 @@
     fun firstPartIsLinearWithEasingOnTheSecondPart() {
         val animation = keyframes<Float> {
             durationMillis = 100
-            0.5f at 50 with FastOutSlowInEasing
+            0.5f at 50 using FastOutSlowInEasing
             1f at durationMillis
         }.vectorize(Float.VectorConverter)
 
@@ -113,7 +113,7 @@
         val easing = FastOutLinearInEasing
         val animation = keyframes<AnimationVector2D> {
             durationMillis = 400
-            AnimationVector(200f, 300f) at 200 with easing
+            AnimationVector(200f, 300f) at 200 using easing
         }.vectorize(TwoWayConverter<AnimationVector2D, AnimationVector2D>({ it }, { it }))
 
         val start = AnimationVector(0f, 0f)
@@ -144,7 +144,7 @@
         val config: KeyframesSpec.KeyframesSpecConfig<Float>.() -> Unit = {
             durationMillis = 500
             0f at 100
-            0.5f at 200 with FastOutLinearInEasing
+            0.5f at 200 using FastOutLinearInEasing
             0.8f at 300
             1f at durationMillis
         }
@@ -156,7 +156,7 @@
         val animationRedeclareConfig = keyframes<Float> {
             durationMillis = 500
             0f at 100
-            0.5f at 200 with FastOutLinearInEasing
+            0.5f at 200 using FastOutLinearInEasing
             0.8f at 300
             1f at durationMillis
         }
@@ -174,7 +174,7 @@
         val animation = keyframes<Float> {
             durationMillis = 500
             0f at 100
-            0.5f at 200 with FastOutLinearInEasing
+            0.5f at 200 using FastOutLinearInEasing
             0.8f at 300
             1f at durationMillis
         }
@@ -182,14 +182,14 @@
         val animationAlteredDuration = keyframes<Float> {
             durationMillis = 700
             0f at 100
-            0.5f at 200 with FastOutLinearInEasing
+            0.5f at 200 using FastOutLinearInEasing
             0.8f at 300
             1f at durationMillis
         }
 
         val animationAlteredEasing = keyframes<Float> {
             durationMillis = 500
-            0f at 100 with FastOutSlowInEasing
+            0f at 100 using FastOutSlowInEasing
             0.5f at 200
             0.8f at 300
             1f at durationMillis
@@ -198,7 +198,7 @@
         val animationAlteredKeyframes = keyframes<Float> {
             durationMillis = 500
             0f at 100
-            0.3f at 200 with FastOutLinearInEasing
+            0.3f at 200 using FastOutLinearInEasing
             0.8f at 400
             1f at durationMillis
         }
@@ -230,7 +230,7 @@
     fun percentageBasedKeyframesWithEasing() {
         val animation = keyframes<Float> {
             durationMillis = 100
-            0.5f atFraction 0.5f with FastOutSlowInEasing
+            0.5f atFraction 0.5f using FastOutSlowInEasing
             1f atFraction 1f
         }.vectorize(Float.VectorConverter)
 
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
index e280595..9244266 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
@@ -17,6 +17,7 @@
 package androidx.compose.animation.core
 
 import androidx.annotation.IntRange
+import androidx.collection.mutableIntObjectMapOf
 import androidx.compose.animation.core.AnimationConstants.DefaultDurationMillis
 import androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig
 import androidx.compose.runtime.Immutable
@@ -392,6 +393,85 @@
 }
 
 /**
+ * Shared configuration class used as DSL for keyframe based animations.
+ */
+sealed class KeyframesSpecBaseConfig<T, E : KeyframeBaseEntity<T>> {
+    /**
+     * Duration of the animation in milliseconds. The minimum is `0` and defaults to
+     * [DefaultDurationMillis]
+     */
+    @get:IntRange(from = 0)
+    var durationMillis: Int = DefaultDurationMillis
+
+    /**
+     * The amount of time that the animation should be delayed. The minimum is `0` and defaults
+     * to 0.
+     */
+    @get:IntRange(from = 0)
+    var delayMillis: Int = 0
+
+    internal val keyframes = mutableIntObjectMapOf<E>()
+
+    /**
+     * Method used to delegate instantiation of [E] to implementing classes.
+     */
+    internal abstract fun createEntityFor(value: T): E
+
+    /**
+     * Adds a keyframe so that animation value will be [this] at time: [timeStamp]. For example:
+     *
+     * @sample androidx.compose.animation.core.samples.floatAtSample
+     *
+     * @param timeStamp The time in the during when animation should reach value: [this], with
+     * a minimum value of `0`.
+     * @return an instance of [E] so a custom [Easing] can be added by the [using] method.
+     */
+    infix fun T.at(@IntRange(from = 0) timeStamp: Int): E {
+        val entity = createEntityFor(this)
+        keyframes[timeStamp] = entity
+        return entity
+    }
+
+    /**
+     * Adds a keyframe so that the animation value will be the value specified at a fraction of the
+     * total [durationMillis] set. It's recommended that you always set [durationMillis] before
+     * calling [atFraction]. For example:
+     *
+     * @sample androidx.compose.animation.core.samples.floatAtFractionSample
+     *
+     *  @param fraction The fraction when the animation should reach specified value.
+     *  @return an instance of [E] so a custom [Easing] can be added by the [using] method
+     */
+    infix fun T.atFraction(fraction: Float): E {
+        return at((durationMillis * fraction).roundToInt())
+    }
+
+    /**
+     * Adds an [Easing] for the interval started with the just provided timestamp. For example:
+     *     0f at 50 using LinearEasing
+     *
+     * @sample androidx.compose.animation.core.samples.KeyframesBuilderWithEasing
+     * @param easing [Easing] to be used for the next interval.
+     * @return the same [E] instance so that other implementations can expand on the builder pattern
+     */
+    infix fun E.using(easing: Easing): E {
+        this.easing = easing
+        return this
+    }
+}
+
+/**
+ * Base holder class for building a keyframes animation.
+ */
+sealed class KeyframeBaseEntity<T>(
+    internal val value: T,
+    internal var easing: Easing
+) {
+    internal fun <V : AnimationVector> toPair(convertToVector: (T) -> V) =
+        convertToVector.invoke(value) to easing
+}
+
+/**
  * [KeyframesSpec] creates a [VectorizedKeyframesSpec] animation.
  *
  * [VectorizedKeyframesSpec] animates based on the values defined at different timestamps in
@@ -417,48 +497,8 @@
      * @sample androidx.compose.animation.core.samples.KeyframesBuilderForPosition
      * @see keyframes
      */
-    class KeyframesSpecConfig<T> {
-        /**
-         * Duration of the animation in milliseconds. The minimum is `0` and defaults to
-         * [DefaultDurationMillis]
-         */
-        @get:IntRange(from = 0)
-        var durationMillis: Int = DefaultDurationMillis
-
-        /**
-         * The amount of time that the animation should be delayed. The minimum is `0` and defaults
-         * to 0.
-         */
-        @get:IntRange(from = 0)
-        var delayMillis: Int = 0
-
-        internal val keyframes = mutableMapOf<Int, KeyframeEntity<T>>()
-
-        /**
-         * Adds a keyframe so that animation value will be [this] at time: [timeStamp]. For example:
-         *     0.8f at 150 // ms
-         *
-         * @param timeStamp The time in the during when animation should reach value: [this], with
-         * a minimum value of `0`.
-         * @return an [KeyframeEntity] so a custom [Easing] can be added by [with] method.
-         */
-        // TODO: Need a IntRange equivalent annotation
-        infix fun T.at(@IntRange(from = 0) timeStamp: Int): KeyframeEntity<T> {
-            return KeyframeEntity(this).also {
-                keyframes[timeStamp] = it
-            }
-        }
-
-        /**
-         * Adds a keyframe so that the animation value will be the value specified at a fraction of the total
-         * [durationMillis] set. For example:
-         *      0.8f atFraction 0.50f // half of the overall duration set
-         *  @param fraction The fraction when the animation should reach specified value.
-         *  @return an [KeyframeEntity] so a custom [Easing] can be added by [with] method
-         */
-        infix fun T.atFraction(fraction: Float): KeyframeEntity<T> {
-            return at((durationMillis * fraction).roundToInt())
-        }
+    class KeyframesSpecConfig<T> : KeyframesSpecBaseConfig<T, KeyframeEntity<T>>() {
+        override fun createEntityFor(value: T): KeyframeEntity<T> = KeyframeEntity(value)
 
         /**
          * Adds an [Easing] for the interval started with the just provided timestamp. For example:
@@ -466,7 +506,14 @@
          *
          * @sample androidx.compose.animation.core.samples.KeyframesBuilderWithEasing
          * @param easing [Easing] to be used for the next interval.
+         * @return the same [KeyframeEntity] instance so that other implementations can expand on
+         * the builder pattern
          */
+        @Deprecated(
+            message = "Use version that returns an instance of the entity so it can be re-used" +
+                " in other keyframe builders.",
+            replaceWith = ReplaceWith("this using easing") // Expected usage pattern
+        )
         infix fun KeyframeEntity<T>.with(easing: Easing) {
             this.easing = easing
         }
@@ -482,8 +529,7 @@
     }
 
     override fun equals(other: Any?): Boolean {
-        return other is KeyframesSpec<*> &&
-            config == other.config
+        return other is KeyframesSpec<*> && config == other.config
     }
 
     override fun hashCode(): Int {
@@ -493,11 +539,15 @@
     override fun <V : AnimationVector> vectorize(
         converter: TwoWayConverter<T, V>
     ): VectorizedKeyframesSpec<V> {
+        @SuppressWarnings("PrimitiveInCollection") // Consumed by stable public API
+        val vectorizedKeyframes = mutableMapOf<Int, Pair<V, Easing>>()
+        config.keyframes.forEach { key, value ->
+            vectorizedKeyframes[key] = value.toPair(converter.convertToVector)
+        }
         return VectorizedKeyframesSpec(
-            config.keyframes.mapValues {
-                it.value.toPair(converter.convertToVector)
-            },
-            config.durationMillis, config.delayMillis
+            keyframes = vectorizedKeyframes,
+            durationMillis = config.durationMillis,
+            delayMillis = config.delayMillis
         )
     }
 
@@ -505,11 +555,9 @@
      * Holder class for building a keyframes animation.
      */
     class KeyframeEntity<T> internal constructor(
-        internal val value: T,
-        internal var easing: Easing = LinearEasing
-    ) {
-        internal fun <V : AnimationVector> toPair(convertToVector: (T) -> V) =
-            convertToVector.invoke(value) to easing
+        value: T,
+        easing: Easing = LinearEasing
+    ) : KeyframeBaseEntity<T>(value = value, easing = easing) {
 
         override fun equals(other: Any?): Boolean {
             return other is KeyframeEntity<*> && other.value == value && other.easing == easing
diff --git a/compose/animation/animation-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/animation/graphics/vector/AnimatorAnimationSpecsTest.kt b/compose/animation/animation-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/animation/graphics/vector/AnimatorAnimationSpecsTest.kt
index fb49907..f77439a 100644
--- a/compose/animation/animation-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/animation/graphics/vector/AnimatorAnimationSpecsTest.kt
+++ b/compose/animation/animation-graphics/src/androidInstrumentedTest/kotlin/androidx/compose/animation/graphics/vector/AnimatorAnimationSpecsTest.kt
@@ -78,9 +78,9 @@
                 transitionSpec = {
                     keyframes {
                         durationMillis = 1000
-                        0f at 0 with LinearEasing
-                        100f at 100 with LinearEasing
-                        1000f at 1000 with LinearEasing
+                        0f at 0 using LinearEasing
+                        100f at 100 using LinearEasing
+                        1000f at 1000 using LinearEasing
                     }
                 }
             ) {
@@ -91,9 +91,9 @@
                 transitionSpec = {
                     keyframes<Float> {
                         durationMillis = 1000
-                        1000f at 0 with LinearEasing
-                        100f at 900 with LinearEasing
-                        0f at 1000 with LinearEasing
+                        1000f at 0 using LinearEasing
+                        100f at 900 using LinearEasing
+                        0f at 1000 using LinearEasing
                     }.reversed(1000)
                 }
             ) {
@@ -117,8 +117,8 @@
                 transitionSpec = {
                     keyframes {
                         durationMillis = 1000
-                        0f at 0 with LinearEasing
-                        1000f at 500 with LinearEasing
+                        0f at 0 using LinearEasing
+                        1000f at 500 using LinearEasing
                     }
                 }
             ) {
@@ -129,9 +129,9 @@
                 transitionSpec = {
                     keyframes<Float> {
                         durationMillis = 1000
-                        1000f at 0 with LinearEasing
-                        1000f at 500 with LinearEasing
-                        0f at 1000 with LinearEasing
+                        1000f at 0 using LinearEasing
+                        1000f at 500 using LinearEasing
+                        0f at 1000 using LinearEasing
                     }.reversed(1000)
                 }
             ) {
@@ -186,8 +186,8 @@
                 transitionSpec = {
                     keyframes {
                         durationMillis = 1000
-                        0f at 0 with LinearEasing
-                        1000f at 1000 with LinearEasing
+                        0f at 0 using LinearEasing
+                        1000f at 1000 using LinearEasing
                     }
                 }
             ) {
@@ -200,13 +200,13 @@
                         listOf(
                             0 to keyframes {
                                 durationMillis = 300
-                                0f at 0 with LinearEasing
-                                300f at 300 with LinearEasing
+                                0f at 0 using LinearEasing
+                                300f at 300 using LinearEasing
                             },
                             300 to keyframes {
                                 durationMillis = 700
-                                300f at 0 with LinearEasing
-                                1000f at 700 with LinearEasing
+                                300f at 0 using LinearEasing
+                                1000f at 700 using LinearEasing
                             }
                         )
                     )
diff --git a/compose/animation/animation-graphics/src/commonMain/kotlin/androidx/compose/animation/graphics/vector/Animator.kt b/compose/animation/animation-graphics/src/commonMain/kotlin/androidx/compose/animation/graphics/vector/Animator.kt
index d4ffb83..56f2de5 100644
--- a/compose/animation/animation-graphics/src/commonMain/kotlin/androidx/compose/animation/graphics/vector/Animator.kt
+++ b/compose/animation/animation-graphics/src/commonMain/kotlin/androidx/compose/animation/graphics/vector/Animator.kt
@@ -384,7 +384,7 @@
         return keyframes {
             durationMillis = duration
             animatorKeyframes.fastForEach { keyframe ->
-                keyframe.value at (duration * keyframe.fraction).toInt() with keyframe.interpolator
+                keyframe.value at (duration * keyframe.fraction).toInt() using keyframe.interpolator
             }
         }
     }
@@ -404,7 +404,7 @@
         return keyframes {
             durationMillis = duration
             animatorKeyframes.fastForEach { keyframe ->
-                keyframe.value at (duration * keyframe.fraction).toInt() with keyframe.interpolator
+                keyframe.value at (duration * keyframe.fraction).toInt() using keyframe.interpolator
             }
         }
     }
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/statetransition/RepeatedRotationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/statetransition/RepeatedRotationDemo.kt
index eccdd75..96a75fd 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/statetransition/RepeatedRotationDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/statetransition/RepeatedRotationDemo.kt
@@ -74,7 +74,7 @@
                         iterations = 10,
                         animation = keyframes {
                             durationMillis = 1000
-                            0f at 0 with LinearEasing
+                            0f at 0 using LinearEasing
                             360f at 1000
                         }
                     )
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/vectorgraphics/AnimatedVectorGraphicsDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/vectorgraphics/AnimatedVectorGraphicsDemo.kt
index 4ffe170..8e59114 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/vectorgraphics/AnimatedVectorGraphicsDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/vectorgraphics/AnimatedVectorGraphicsDemo.kt
@@ -111,7 +111,7 @@
                     keyframes {
                         durationMillis = duration
                         0f at 0
-                        360f at duration with LinearEasing
+                        360f at duration using LinearEasing
                     }
                 } else {
                     spring(
@@ -175,7 +175,7 @@
                         keyframes {
                             durationMillis = duration
                             Color.Red at 0
-                            Color.Blue at duration with LinearEasing
+                            Color.Blue at duration using LinearEasing
                         }
                     } else {
                         spring()
diff --git a/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt b/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
index 2f62fcb..469f5c7 100644
--- a/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
+++ b/compose/animation/animation/src/androidInstrumentedTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
@@ -115,9 +115,9 @@
                                 SizeTransform { initialSize, targetSize ->
                                     keyframes {
                                         durationMillis = 320
-                                        IntSize(targetSize.width, initialSize.height) at 160 with
+                                        IntSize(targetSize.width, initialSize.height) at 160 using
                                             LinearEasing
-                                        targetSize at 320 with LinearEasing
+                                        targetSize at 320 using LinearEasing
                                     }
                                 }
                         } else {
@@ -809,8 +809,8 @@
                         } using SizeTransform { initialSize, targetSize ->
                             keyframes {
                                 durationMillis = 300
-                                initialSize at 100 with LinearEasing
-                                targetSize at 200 with LinearEasing
+                                initialSize at 100 using LinearEasing
+                                targetSize at 200 using LinearEasing
                             }
                         }
                     }) {
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/LoremIpsum.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/LoremIpsum.kt
index 42511ed..62c54c3 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/LoremIpsum.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/LoremIpsum.kt
@@ -26,9 +26,10 @@
 
 fun loremIpsum(
     language: Language = Language.Latin,
-    wordCount: Int = language.words.size
+    wordCount: Int = language.words.size,
+    separator: CharSequence = " ",
 ): String =
-    loremIpsumWords(language).joinToString(separator = " ", limit = wordCount, truncated = "")
+    loremIpsumWords(language).joinToString(separator = separator, limit = wordCount, truncated = "")
 
 /**
  * An infinite [Sequence] of words of Lorem Ipsum text.
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
index f7bfe30..b7ef02f 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text/TextDemos.kt
@@ -25,6 +25,7 @@
 import androidx.compose.foundation.demos.text2.DecorationBoxDemos
 import androidx.compose.foundation.demos.text2.KeyboardOptionsDemos
 import androidx.compose.foundation.demos.text2.ScrollableDemos
+import androidx.compose.foundation.demos.text2.ScrollableDemosRtl
 import androidx.compose.foundation.demos.text2.SwapFieldSameStateDemo
 import androidx.compose.foundation.demos.text2.TextFieldLineLimitsDemos
 import androidx.compose.foundation.samples.BasicTextField2UndoSample
@@ -141,7 +142,10 @@
                 ComposableDemo("Keyboard Options") { KeyboardOptionsDemos() },
                 ComposableDemo("Decoration Box") { DecorationBoxDemos() },
                 ComposableDemo("Line limits") { TextFieldLineLimitsDemos() },
-                ComposableDemo("Scroll") { ScrollableDemos() },
+                DemoCategory("Scroll", listOf(
+                    ComposableDemo("Ltr") { ScrollableDemos() },
+                    ComposableDemo("Rtl") { ScrollableDemosRtl() },
+                )),
                 ComposableDemo("Filters") { BasicTextField2FilterDemos() },
                 ComposableDemo("Secure Field") { BasicSecureTextFieldDemos() },
                 ComposableDemo("Swap the field but reuse the state") { SwapFieldSameStateDemo() },
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt
index af8e58c..00eb85c 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/DecorationBoxDemos.kt
@@ -40,7 +40,7 @@
 
 @Composable
 fun DecorationBoxDemos() {
-    Column {
+    Column(Modifier.padding(16.dp)) {
         TagLine(tag = "Simple Decoration w/ Label")
         SimpleDecorationWithLabel()
 
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt
index b144879..0888591 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/src/main/java/androidx/compose/foundation/demos/text2/ScrollDemos.kt
@@ -17,8 +17,8 @@
 package androidx.compose.foundation.demos.text2
 
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.demos.text.Language
 import androidx.compose.foundation.demos.text.TagLine
-import androidx.compose.foundation.demos.text.fontSize8
 import androidx.compose.foundation.demos.text.loremIpsum
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
@@ -31,18 +31,15 @@
 import androidx.compose.foundation.text2.input.TextFieldLineLimits.MultiLine
 import androidx.compose.foundation.text2.input.TextFieldLineLimits.SingleLine
 import androidx.compose.foundation.text2.input.TextFieldState
-import androidx.compose.material.Button
 import androidx.compose.material.Slider
-import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.FocusRequester
-import androidx.compose.ui.focus.focusRequester
-import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.coerceIn
+import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import kotlin.math.roundToInt
@@ -62,11 +59,6 @@
         }
 
         item {
-            TagLine(tag = "SingleLine Vertical Scroll")
-            SingleLineVerticalScrollableTextField()
-        }
-
-        item {
             TagLine(tag = "MultiLine Vertical Scroll")
             MultiLineVerticalScrollableTextField()
         }
@@ -80,19 +72,28 @@
             TagLine(tag = "Shared Hoisted ScrollState")
             SharedHoistedScroll()
         }
+    }
+}
 
-        item {
-            TagLine(tag = "Selectable with no interaction")
-            SelectionWithNoInteraction()
-        }
+@Composable
+fun ScrollableDemosRtl() {
+    CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
+        ScrollableDemos()
     }
 }
 
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
 fun SingleLineHorizontalScrollableTextField() {
-    val state = remember {
-        TextFieldState(loremIpsum(wordCount = 100))
+    val layoutDirection = LocalLayoutDirection.current
+    val language = if (layoutDirection == LayoutDirection.Ltr) Language.Latin else Language.Hebrew
+    val state = remember(language) {
+        TextFieldState(
+            loremIpsum(
+                wordCount = 100,
+                language = language
+            )
+        )
     }
     BasicTextField2(
         state = state,
@@ -102,12 +103,19 @@
     )
 }
 
-// TODO this is not supported currently. Add tests for this when supported.
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
 fun SingleLineHorizontalScrollableTextFieldWithNewlines() {
-    val state = remember {
-        TextFieldState("This \ntext \ncontains \nnewlines \nbut \nis \nsingle-line.")
+    val layoutDirection = LocalLayoutDirection.current
+    val language = if (layoutDirection == LayoutDirection.Ltr) Language.Latin else Language.Hebrew
+    val state = remember(language) {
+        TextFieldState(
+            loremIpsum(
+                wordCount = 20,
+                language = language,
+                separator = "\n"
+            )
+        )
     }
     BasicTextField2(
         state = state,
@@ -118,22 +126,16 @@
 
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
-fun SingleLineVerticalScrollableTextField() {
-    val state = remember {
-        TextFieldState("When content gets long, this field should scroll vertically\n".repeat(10))
-    }
-    BasicTextField2(
-        state = state,
-        textStyle = TextStyle(fontSize = 24.sp),
-        lineLimits = MultiLine(maxHeightInLines = 1)
-    )
-}
-
-@OptIn(ExperimentalFoundationApi::class)
-@Composable
 fun MultiLineVerticalScrollableTextField() {
-    val state = remember {
-        TextFieldState(loremIpsum(wordCount = 200))
+    val layoutDirection = LocalLayoutDirection.current
+    val language = if (layoutDirection == LayoutDirection.Ltr) Language.Latin else Language.Hebrew
+    val state = remember(language) {
+        TextFieldState(
+            loremIpsum(
+                wordCount = 200,
+                language = language
+            )
+        )
     }
     BasicTextField2(
         state = state,
@@ -146,8 +148,15 @@
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
 fun HoistedHorizontalScroll() {
-    val state = remember {
-        TextFieldState("When content gets long, this field should scroll horizontally")
+    val layoutDirection = LocalLayoutDirection.current
+    val language = if (layoutDirection == LayoutDirection.Ltr) Language.Latin else Language.Hebrew
+    val state = remember(language) {
+        TextFieldState(
+            loremIpsum(
+                wordCount = 20,
+                language = language
+            )
+        )
     }
     val scrollState = rememberScrollState()
     val coroutineScope = rememberCoroutineScope()
@@ -172,11 +181,23 @@
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
 fun SharedHoistedScroll() {
-    val state1 = remember {
-        TextFieldState("When content gets long, this field should scroll horizontally")
+    val layoutDirection = LocalLayoutDirection.current
+    val language = if (layoutDirection == LayoutDirection.Ltr) Language.Latin else Language.Hebrew
+    val state1 = remember(language) {
+        TextFieldState(
+            loremIpsum(
+                wordCount = 20,
+                language = language
+            )
+        )
     }
-    val state2 = remember {
-        TextFieldState("When content gets long, this field should scroll horizontally")
+    val state2 = remember(language) {
+        TextFieldState(
+            loremIpsum(
+                wordCount = 20,
+                language = language
+            )
+        )
     }
     val scrollState = rememberScrollState()
     val coroutineScope = rememberCoroutineScope()
@@ -204,46 +225,3 @@
         )
     }
 }
-
-@OptIn(ExperimentalFoundationApi::class)
-@Composable
-fun SelectionWithNoInteraction() {
-    val state =
-        remember { TextFieldState("Hello, World!", initialSelectionInChars = TextRange(1, 5)) }
-    val focusRequester = remember { FocusRequester() }
-    Column {
-        Button(onClick = { focusRequester.requestFocus() }) {
-            Text("Focus")
-        }
-        Button(onClick = {
-            state.edit {
-                selectCharsIn(
-                    TextRange(
-                        state.text.selectionInChars.start - 1,
-                        state.text.selectionInChars.end
-                    ).coerceIn(0, state.text.length)
-                )
-            }
-        }) {
-            Text("Increase Selection to Left")
-        }
-        Button(onClick = {
-            state.edit {
-                selectCharsIn(
-                    TextRange(
-                        state.text.selectionInChars.start,
-                        state.text.selectionInChars.end + 1
-                    ).coerceIn(0, state.text.length)
-                )
-            }
-        }) {
-            Text("Increase Selection to Right")
-        }
-        BasicTextField2(
-            state = state,
-            modifier = demoTextFieldModifiers.focusRequester(focusRequester),
-            textStyle = TextStyle(fontSize = fontSize8),
-            lineLimits = SingleLine
-        )
-    }
-}
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/AndroidExternalSurfaceTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/AndroidExternalSurfaceTest.kt
index 59bb5f8..3254191 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/AndroidExternalSurfaceTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/AndroidExternalSurfaceTest.kt
@@ -16,6 +16,9 @@
 
 package androidx.compose.foundation
 
+import android.app.Activity
+import android.content.Context
+import android.content.ContextWrapper
 import android.graphics.Bitmap
 import android.graphics.PorterDuff
 import android.graphics.Rect
@@ -26,6 +29,7 @@
 import android.view.PixelCopy
 import android.view.Surface
 import android.view.View
+import android.view.Window
 import androidx.annotation.RequiresApi
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.size
@@ -55,10 +59,12 @@
 import androidx.core.graphics.ColorUtils
 import androidx.core.graphics.createBitmap
 import androidx.test.core.internal.os.HandlerExecutor
+import androidx.test.core.view.forceRedraw
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.platform.graphics.HardwareRendererCompat
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.ExecutionException
 import java.util.concurrent.TimeUnit
@@ -508,52 +514,57 @@
 
     val node = fetchSemanticsNode()
     val view = (node.root as ViewRootForTest).view
+    val window = view.context.getActivityWindow()
 
-    val bitmapFuture: ResolvableFuture<Bitmap> = ResolvableFuture.create()
+    return withDrawingEnabled {
+        val bitmapFuture: ResolvableFuture<Bitmap> = ResolvableFuture.create()
 
-    val mainExecutor = HandlerExecutor(Handler(Looper.getMainLooper()))
-    mainExecutor.execute {
-        Choreographer.getInstance().postFrameCallback {
-            val location = IntArray(2)
-            view.getLocationOnScreen(location)
+        val mainExecutor = HandlerExecutor(Handler(Looper.getMainLooper()))
+        mainExecutor.execute {
+            window.decorView.forceRedraw()
 
-            val bounds = node.boundsInRoot.translate(
-                location[0].toFloat(),
-                location[1].toFloat()
-            )
+            Choreographer.getInstance().postFrameCallback {
+                val location = IntArray(2)
+                view.getLocationOnScreen(location)
 
-            // do multiple retries of uiAutomation.takeScreenshot because it is known to return null
-            // on API 31+ b/257274080
-            var bitmap: Bitmap? = null
-            var i = 0
-            while (i < 3 && bitmap == null) {
-                bitmap = uiAutomation.takeScreenshot()
-                i++
-            }
-
-            if (bitmap != null) {
-                bitmap = Bitmap.createBitmap(
-                    bitmap,
-                    bounds.left.toInt(),
-                    bounds.top.toInt(),
-                    bounds.width.toInt(),
-                    bounds.height.toInt()
+                val bounds = node.boundsInRoot.translate(
+                    location[0].toFloat(),
+                    location[1].toFloat()
                 )
-                bitmapFuture.set(bitmap)
-            } else {
-                if (hasSecureSurfaces) {
-                    // may be null on older API levels when a secure surface is showing
-                    bitmapFuture.set(null)
+
+                // do multiple retries of uiAutomation.takeScreenshot because it is known to return null
+                // on API 31+ b/257274080
+                var bitmap: Bitmap? = null
+                var i = 0
+                while (i < 3 && bitmap == null) {
+                    bitmap = uiAutomation.takeScreenshot()
+                    i++
                 }
-                // if we don't show secure surfaces, let the future timeout on get()
+
+                if (bitmap != null) {
+                    bitmap = Bitmap.createBitmap(
+                        bitmap,
+                        bounds.left.toInt(),
+                        bounds.top.toInt(),
+                        bounds.width.toInt(),
+                        bounds.height.toInt()
+                    )
+                    bitmapFuture.set(bitmap)
+                } else {
+                    if (hasSecureSurfaces) {
+                        // may be null on older API levels when a secure surface is showing
+                        bitmapFuture.set(null)
+                    }
+                    // if we don't show secure surfaces, let the future timeout on get()
+                }
             }
         }
-    }
 
-    return try {
-        bitmapFuture.get(5, TimeUnit.SECONDS)?.asImageBitmap()
-    } catch (e: ExecutionException) {
-        null
+        try {
+            bitmapFuture.get(5, TimeUnit.SECONDS)?.asImageBitmap()
+        } catch (e: ExecutionException) {
+            null
+        }
     }
 }
 
@@ -587,3 +598,31 @@
 
     return bitmap.asImageBitmap()
 }
+
+private fun <R> withDrawingEnabled(block: () -> R): R {
+    val wasDrawingEnabled = HardwareRendererCompat.isDrawingEnabled()
+    try {
+        if (!wasDrawingEnabled) {
+            HardwareRendererCompat.setDrawingEnabled(true)
+        }
+        return block.invoke()
+    } finally {
+        if (!wasDrawingEnabled) {
+            HardwareRendererCompat.setDrawingEnabled(false)
+        }
+    }
+}
+
+private fun Context.getActivityWindow(): Window {
+    fun Context.getActivity(): Activity {
+        return when (this) {
+            is Activity -> this
+            is ContextWrapper -> this.baseContext.getActivity()
+            else -> throw IllegalStateException(
+                "Context is not an Activity context, but a ${javaClass.simpleName} context. " +
+                    "An Activity context is required to get a Window instance"
+            )
+        }
+    }
+    return getActivity().window
+}
diff --git a/compose/material/material-icons-core/api/current.txt b/compose/material/material-icons-core/api/current.txt
index e9e6d3b..c80a502 100644
--- a/compose/material/material-icons-core/api/current.txt
+++ b/compose/material/material-icons-core/api/current.txt
@@ -54,8 +54,8 @@
   }
 
   public final class IconsKt {
-    method public static inline androidx.compose.ui.graphics.vector.ImageVector materialIcon(String name, boolean autoMirror, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.ImageVector.Builder,androidx.compose.ui.graphics.vector.ImageVector.Builder> block);
-    method public static inline androidx.compose.ui.graphics.vector.ImageVector materialIcon(String name, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.ImageVector.Builder,androidx.compose.ui.graphics.vector.ImageVector.Builder> block);
+    method public static inline androidx.compose.ui.graphics.vector.ImageVector materialIcon(String name, optional boolean autoMirror, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.ImageVector.Builder,androidx.compose.ui.graphics.vector.ImageVector.Builder> block);
+    method @Deprecated public static inline androidx.compose.ui.graphics.vector.ImageVector materialIcon(String name, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.ImageVector.Builder,androidx.compose.ui.graphics.vector.ImageVector.Builder> block);
     method public static inline androidx.compose.ui.graphics.vector.ImageVector.Builder materialPath(androidx.compose.ui.graphics.vector.ImageVector.Builder, optional float fillAlpha, optional float strokeAlpha, optional int pathFillType, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.PathBuilder,kotlin.Unit> pathBuilder);
   }
 
diff --git a/compose/material/material-icons-core/api/restricted_current.txt b/compose/material/material-icons-core/api/restricted_current.txt
index d5e5415..06acb8e 100644
--- a/compose/material/material-icons-core/api/restricted_current.txt
+++ b/compose/material/material-icons-core/api/restricted_current.txt
@@ -54,8 +54,8 @@
   }
 
   public final class IconsKt {
-    method public static inline androidx.compose.ui.graphics.vector.ImageVector materialIcon(String name, boolean autoMirror, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.ImageVector.Builder,androidx.compose.ui.graphics.vector.ImageVector.Builder> block);
-    method public static inline androidx.compose.ui.graphics.vector.ImageVector materialIcon(String name, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.ImageVector.Builder,androidx.compose.ui.graphics.vector.ImageVector.Builder> block);
+    method public static inline androidx.compose.ui.graphics.vector.ImageVector materialIcon(String name, optional boolean autoMirror, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.ImageVector.Builder,androidx.compose.ui.graphics.vector.ImageVector.Builder> block);
+    method @Deprecated public static inline androidx.compose.ui.graphics.vector.ImageVector materialIcon(String name, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.ImageVector.Builder,androidx.compose.ui.graphics.vector.ImageVector.Builder> block);
     method public static inline androidx.compose.ui.graphics.vector.ImageVector.Builder materialPath(androidx.compose.ui.graphics.vector.ImageVector.Builder, optional float fillAlpha, optional float strokeAlpha, optional int pathFillType, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.vector.PathBuilder,kotlin.Unit> pathBuilder);
     field @kotlin.PublishedApi internal static final float MaterialIconDimension = 24.0f;
   }
diff --git a/compose/material/material-icons-core/src/commonMain/kotlin/androidx/compose/material/icons/Icons.kt b/compose/material/material-icons-core/src/commonMain/kotlin/androidx/compose/material/icons/Icons.kt
index 3573a8d..30f8b7d 100644
--- a/compose/material/material-icons-core/src/commonMain/kotlin/androidx/compose/material/icons/Icons.kt
+++ b/compose/material/material-icons-core/src/commonMain/kotlin/androidx/compose/material/icons/Icons.kt
@@ -191,6 +191,10 @@
  * @param name the full name of the generated icon
  * @param block builder lambda to add paths to this vector asset
  */
+@Deprecated(
+    "Maintained for binary compatibility. Use version with autoMirror instead.",
+    level = DeprecationLevel.HIDDEN
+)
 inline fun materialIcon(
     name: String,
     block: ImageVector.Builder.() -> ImageVector.Builder
@@ -207,7 +211,7 @@
  */
 inline fun materialIcon(
     name: String,
-    autoMirror: Boolean,
+    autoMirror: Boolean = false,
     block: ImageVector.Builder.() -> ImageVector.Builder
 ): ImageVector = ImageVector.Builder(
     name = name,
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt
index f10015e..9be72a8 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt
@@ -151,7 +151,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = LinearAnimationDuration
-                0f at FirstLineHeadDelay with FirstLineHeadEasing
+                0f at FirstLineHeadDelay using FirstLineHeadEasing
                 1f at FirstLineHeadDuration + FirstLineHeadDelay
             }
         )
@@ -162,7 +162,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = LinearAnimationDuration
-                0f at FirstLineTailDelay with FirstLineTailEasing
+                0f at FirstLineTailDelay using FirstLineTailEasing
                 1f at FirstLineTailDuration + FirstLineTailDelay
             }
         )
@@ -173,7 +173,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = LinearAnimationDuration
-                0f at SecondLineHeadDelay with SecondLineHeadEasing
+                0f at SecondLineHeadDelay using SecondLineHeadEasing
                 1f at SecondLineHeadDuration + SecondLineHeadDelay
             }
         )
@@ -184,7 +184,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = LinearAnimationDuration
-                0f at SecondLineTailDelay with SecondLineTailEasing
+                0f at SecondLineTailDelay using SecondLineTailEasing
                 1f at SecondLineTailDuration + SecondLineTailDelay
             }
         )
@@ -398,7 +398,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = HeadAndTailAnimationDuration + HeadAndTailDelayDuration
-                0f at 0 with CircularEasing
+                0f at 0 using CircularEasing
                 JumpRotationAngle at HeadAndTailAnimationDuration
             }
         )
@@ -410,7 +410,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = HeadAndTailAnimationDuration + HeadAndTailDelayDuration
-                0f at HeadAndTailDelayDuration with CircularEasing
+                0f at HeadAndTailDelayDuration using CircularEasing
                 JumpRotationAngle at durationMillis
             }
         )
diff --git a/compose/material3/material3-adaptive/api/current.txt b/compose/material3/material3-adaptive/api/current.txt
index b33820f..cc2cb3d 100644
--- a/compose/material3/material3-adaptive/api/current.txt
+++ b/compose/material3/material3-adaptive/api/current.txt
@@ -11,23 +11,6 @@
     property public final androidx.compose.material3.adaptive.AdaptStrategy Hide;
   }
 
-  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class AdaptiveLayoutDirective {
-    ctor public AdaptiveLayoutDirective(int maxHorizontalPartitions, androidx.compose.material3.adaptive.GutterSizes gutterSizes, int maxVerticalPartitions, java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds);
-    method public java.util.List<androidx.compose.ui.geometry.Rect> getExcludedBounds();
-    method public androidx.compose.material3.adaptive.GutterSizes getGutterSizes();
-    method public int getMaxHorizontalPartitions();
-    method public int getMaxVerticalPartitions();
-    property public final java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds;
-    property public final androidx.compose.material3.adaptive.GutterSizes gutterSizes;
-    property public final int maxHorizontalPartitions;
-    property public final int maxVerticalPartitions;
-  }
-
-  public final class AdaptiveLayoutDirectiveKt {
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.AdaptiveLayoutDirective calculateDenseAdaptiveLayoutDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int hingePolicy);
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.AdaptiveLayoutDirective calculateStandardAdaptiveLayoutDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int hingePolicy);
-  }
-
   public final class AndroidPosture_androidKt {
     method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.Posture calculatePosture(java.util.List<? extends androidx.window.layout.FoldingFeature> foldingFeatures);
   }
@@ -75,7 +58,7 @@
 
   public final class ListDetailPaneScaffoldKt {
     method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ListDetailPaneScaffold(androidx.compose.material3.adaptive.ListDetailPaneScaffoldState layoutState, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> listPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit>? extraPane, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> detailPane);
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.ListDetailPaneScaffoldState rememberListDetailPaneScaffoldState(optional androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirectives, optional androidx.compose.material3.adaptive.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional java.util.List<? extends androidx.compose.material3.adaptive.ListDetailPaneScaffoldRole> initialFocusHistory);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.ListDetailPaneScaffoldState rememberListDetailPaneScaffoldState(optional androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional java.util.List<? extends androidx.compose.material3.adaptive.ListDetailPaneScaffoldRole> initialFocusHistory);
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum ListDetailPaneScaffoldRole {
@@ -88,12 +71,12 @@
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface ListDetailPaneScaffoldState {
     method public boolean canNavigateBack(optional boolean layoutValueMustChange);
-    method public androidx.compose.material3.adaptive.AdaptiveLayoutDirective getLayoutDirective();
     method public androidx.compose.material3.adaptive.ThreePaneScaffoldValue getLayoutValue();
+    method public androidx.compose.material3.adaptive.PaneScaffoldDirective getScaffoldDirective();
     method public boolean navigateBack(optional boolean popUntilLayoutValueChange);
     method public void navigateTo(androidx.compose.material3.adaptive.ListDetailPaneScaffoldRole pane);
-    property public abstract androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirective;
     property public abstract androidx.compose.material3.adaptive.ThreePaneScaffoldValue layoutValue;
+    property public abstract androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective;
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteColors {
@@ -164,6 +147,23 @@
     property public final String Hidden;
   }
 
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class PaneScaffoldDirective {
+    ctor public PaneScaffoldDirective(int maxHorizontalPartitions, androidx.compose.material3.adaptive.GutterSizes gutterSizes, int maxVerticalPartitions, java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds);
+    method public java.util.List<androidx.compose.ui.geometry.Rect> getExcludedBounds();
+    method public androidx.compose.material3.adaptive.GutterSizes getGutterSizes();
+    method public int getMaxHorizontalPartitions();
+    method public int getMaxVerticalPartitions();
+    property public final java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds;
+    property public final androidx.compose.material3.adaptive.GutterSizes gutterSizes;
+    property public final int maxHorizontalPartitions;
+    property public final int maxVerticalPartitions;
+  }
+
+  public final class PaneScaffoldDirectiveKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.PaneScaffoldDirective calculateDensePaneScaffoldDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int hingePolicy);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.PaneScaffoldDirective calculateStandardPaneScaffoldDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int hingePolicy);
+  }
+
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface PaneScaffoldScope {
     method public androidx.compose.ui.Modifier preferredWidth(androidx.compose.ui.Modifier, float width);
   }
@@ -187,7 +187,7 @@
 
   public final class SupportingPaneScaffoldKt {
     method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void SupportingPaneScaffold(androidx.compose.material3.adaptive.SupportingPaneScaffoldState scaffoldState, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit>? extraPane, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> mainPane);
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.SupportingPaneScaffoldState rememberSupportingPaneScaffoldState(optional androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirectives, optional androidx.compose.material3.adaptive.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional java.util.List<? extends androidx.compose.material3.adaptive.SupportingPaneScaffoldRole> initialFocusHistory);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.SupportingPaneScaffoldState rememberSupportingPaneScaffoldState(optional androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional java.util.List<? extends androidx.compose.material3.adaptive.SupportingPaneScaffoldRole> initialFocusHistory);
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum SupportingPaneScaffoldRole {
@@ -200,12 +200,12 @@
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface SupportingPaneScaffoldState {
     method public boolean canNavigateBack(optional boolean layoutValueMustChange);
-    method public androidx.compose.material3.adaptive.AdaptiveLayoutDirective getLayoutDirective();
     method public androidx.compose.material3.adaptive.ThreePaneScaffoldValue getLayoutValue();
+    method public androidx.compose.material3.adaptive.PaneScaffoldDirective getScaffoldDirective();
     method public boolean navigateBack(optional boolean popUntilLayoutValueChange);
     method public void navigateTo(androidx.compose.material3.adaptive.SupportingPaneScaffoldRole pane);
-    property public abstract androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirective;
     property public abstract androidx.compose.material3.adaptive.ThreePaneScaffoldValue layoutValue;
+    property public abstract androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective;
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class ThreePaneScaffoldAdaptStrategies {
@@ -237,7 +237,7 @@
   }
 
   public final class ThreePaneScaffoldKt {
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ThreePaneScaffold(androidx.compose.ui.Modifier modifier, androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirective, androidx.compose.material3.adaptive.ThreePaneScaffoldValue scaffoldValue, androidx.compose.material3.adaptive.ThreePaneScaffoldArrangement arrangement, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> secondaryPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit>? tertiaryPane, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> primaryPane);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ThreePaneScaffold(androidx.compose.ui.Modifier modifier, androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective, androidx.compose.material3.adaptive.ThreePaneScaffoldValue scaffoldValue, androidx.compose.material3.adaptive.ThreePaneScaffoldArrangement arrangement, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> secondaryPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit>? tertiaryPane, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> primaryPane);
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum ThreePaneScaffoldRole {
diff --git a/compose/material3/material3-adaptive/api/restricted_current.txt b/compose/material3/material3-adaptive/api/restricted_current.txt
index b33820f..cc2cb3d 100644
--- a/compose/material3/material3-adaptive/api/restricted_current.txt
+++ b/compose/material3/material3-adaptive/api/restricted_current.txt
@@ -11,23 +11,6 @@
     property public final androidx.compose.material3.adaptive.AdaptStrategy Hide;
   }
 
-  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class AdaptiveLayoutDirective {
-    ctor public AdaptiveLayoutDirective(int maxHorizontalPartitions, androidx.compose.material3.adaptive.GutterSizes gutterSizes, int maxVerticalPartitions, java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds);
-    method public java.util.List<androidx.compose.ui.geometry.Rect> getExcludedBounds();
-    method public androidx.compose.material3.adaptive.GutterSizes getGutterSizes();
-    method public int getMaxHorizontalPartitions();
-    method public int getMaxVerticalPartitions();
-    property public final java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds;
-    property public final androidx.compose.material3.adaptive.GutterSizes gutterSizes;
-    property public final int maxHorizontalPartitions;
-    property public final int maxVerticalPartitions;
-  }
-
-  public final class AdaptiveLayoutDirectiveKt {
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.AdaptiveLayoutDirective calculateDenseAdaptiveLayoutDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int hingePolicy);
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.AdaptiveLayoutDirective calculateStandardAdaptiveLayoutDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int hingePolicy);
-  }
-
   public final class AndroidPosture_androidKt {
     method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.Posture calculatePosture(java.util.List<? extends androidx.window.layout.FoldingFeature> foldingFeatures);
   }
@@ -75,7 +58,7 @@
 
   public final class ListDetailPaneScaffoldKt {
     method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ListDetailPaneScaffold(androidx.compose.material3.adaptive.ListDetailPaneScaffoldState layoutState, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> listPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit>? extraPane, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> detailPane);
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.ListDetailPaneScaffoldState rememberListDetailPaneScaffoldState(optional androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirectives, optional androidx.compose.material3.adaptive.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional java.util.List<? extends androidx.compose.material3.adaptive.ListDetailPaneScaffoldRole> initialFocusHistory);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.ListDetailPaneScaffoldState rememberListDetailPaneScaffoldState(optional androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional java.util.List<? extends androidx.compose.material3.adaptive.ListDetailPaneScaffoldRole> initialFocusHistory);
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum ListDetailPaneScaffoldRole {
@@ -88,12 +71,12 @@
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface ListDetailPaneScaffoldState {
     method public boolean canNavigateBack(optional boolean layoutValueMustChange);
-    method public androidx.compose.material3.adaptive.AdaptiveLayoutDirective getLayoutDirective();
     method public androidx.compose.material3.adaptive.ThreePaneScaffoldValue getLayoutValue();
+    method public androidx.compose.material3.adaptive.PaneScaffoldDirective getScaffoldDirective();
     method public boolean navigateBack(optional boolean popUntilLayoutValueChange);
     method public void navigateTo(androidx.compose.material3.adaptive.ListDetailPaneScaffoldRole pane);
-    property public abstract androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirective;
     property public abstract androidx.compose.material3.adaptive.ThreePaneScaffoldValue layoutValue;
+    property public abstract androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective;
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteColors {
@@ -164,6 +147,23 @@
     property public final String Hidden;
   }
 
+  @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Immutable public final class PaneScaffoldDirective {
+    ctor public PaneScaffoldDirective(int maxHorizontalPartitions, androidx.compose.material3.adaptive.GutterSizes gutterSizes, int maxVerticalPartitions, java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds);
+    method public java.util.List<androidx.compose.ui.geometry.Rect> getExcludedBounds();
+    method public androidx.compose.material3.adaptive.GutterSizes getGutterSizes();
+    method public int getMaxHorizontalPartitions();
+    method public int getMaxVerticalPartitions();
+    property public final java.util.List<androidx.compose.ui.geometry.Rect> excludedBounds;
+    property public final androidx.compose.material3.adaptive.GutterSizes gutterSizes;
+    property public final int maxHorizontalPartitions;
+    property public final int maxVerticalPartitions;
+  }
+
+  public final class PaneScaffoldDirectiveKt {
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.PaneScaffoldDirective calculateDensePaneScaffoldDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int hingePolicy);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public static androidx.compose.material3.adaptive.PaneScaffoldDirective calculateStandardPaneScaffoldDirective(androidx.compose.material3.adaptive.WindowAdaptiveInfo windowAdaptiveInfo, optional int hingePolicy);
+  }
+
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface PaneScaffoldScope {
     method public androidx.compose.ui.Modifier preferredWidth(androidx.compose.ui.Modifier, float width);
   }
@@ -187,7 +187,7 @@
 
   public final class SupportingPaneScaffoldKt {
     method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void SupportingPaneScaffold(androidx.compose.material3.adaptive.SupportingPaneScaffoldState scaffoldState, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> supportingPane, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit>? extraPane, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> mainPane);
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.SupportingPaneScaffoldState rememberSupportingPaneScaffoldState(optional androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirectives, optional androidx.compose.material3.adaptive.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional java.util.List<? extends androidx.compose.material3.adaptive.SupportingPaneScaffoldRole> initialFocusHistory);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static androidx.compose.material3.adaptive.SupportingPaneScaffoldState rememberSupportingPaneScaffoldState(optional androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective, optional androidx.compose.material3.adaptive.ThreePaneScaffoldAdaptStrategies adaptStrategies, optional java.util.List<? extends androidx.compose.material3.adaptive.SupportingPaneScaffoldRole> initialFocusHistory);
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum SupportingPaneScaffoldRole {
@@ -200,12 +200,12 @@
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Stable public interface SupportingPaneScaffoldState {
     method public boolean canNavigateBack(optional boolean layoutValueMustChange);
-    method public androidx.compose.material3.adaptive.AdaptiveLayoutDirective getLayoutDirective();
     method public androidx.compose.material3.adaptive.ThreePaneScaffoldValue getLayoutValue();
+    method public androidx.compose.material3.adaptive.PaneScaffoldDirective getScaffoldDirective();
     method public boolean navigateBack(optional boolean popUntilLayoutValueChange);
     method public void navigateTo(androidx.compose.material3.adaptive.SupportingPaneScaffoldRole pane);
-    property public abstract androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirective;
     property public abstract androidx.compose.material3.adaptive.ThreePaneScaffoldValue layoutValue;
+    property public abstract androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective;
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class ThreePaneScaffoldAdaptStrategies {
@@ -237,7 +237,7 @@
   }
 
   public final class ThreePaneScaffoldKt {
-    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ThreePaneScaffold(androidx.compose.ui.Modifier modifier, androidx.compose.material3.adaptive.AdaptiveLayoutDirective layoutDirective, androidx.compose.material3.adaptive.ThreePaneScaffoldValue scaffoldValue, androidx.compose.material3.adaptive.ThreePaneScaffoldArrangement arrangement, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> secondaryPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit>? tertiaryPane, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> primaryPane);
+    method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void ThreePaneScaffold(androidx.compose.ui.Modifier modifier, androidx.compose.material3.adaptive.PaneScaffoldDirective scaffoldDirective, androidx.compose.material3.adaptive.ThreePaneScaffoldValue scaffoldValue, androidx.compose.material3.adaptive.ThreePaneScaffoldArrangement arrangement, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> secondaryPane, optional kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit>? tertiaryPane, kotlin.jvm.functions.Function2<? super androidx.compose.material3.adaptive.ThreePaneScaffoldScope,? super androidx.compose.material3.adaptive.PaneAdaptedValue,kotlin.Unit> primaryPane);
   }
 
   @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum ThreePaneScaffoldRole {
diff --git a/compose/material3/material3-adaptive/samples/src/main/java/androidx/compose/material3-adaptive/samples/ThreePaneScaffoldSample.kt b/compose/material3/material3-adaptive/samples/src/main/java/androidx/compose/material3-adaptive/samples/ThreePaneScaffoldSample.kt
index 943a1a3..42618e3 100644
--- a/compose/material3/material3-adaptive/samples/src/main/java/androidx/compose/material3-adaptive/samples/ThreePaneScaffoldSample.kt
+++ b/compose/material3/material3-adaptive/samples/src/main/java/androidx/compose/material3-adaptive/samples/ThreePaneScaffoldSample.kt
@@ -33,7 +33,7 @@
 import androidx.compose.material3.adaptive.ListDetailPaneScaffoldRole
 import androidx.compose.material3.adaptive.ThreePaneScaffold
 import androidx.compose.material3.adaptive.ThreePaneScaffoldDefaults
-import androidx.compose.material3.adaptive.calculateStandardAdaptiveLayoutDirective
+import androidx.compose.material3.adaptive.calculateStandardPaneScaffoldDirective
 import androidx.compose.material3.adaptive.calculateThreePaneScaffoldValue
 import androidx.compose.material3.adaptive.calculateWindowAdaptiveInfo
 import androidx.compose.material3.adaptive.rememberListDetailPaneScaffoldState
@@ -162,11 +162,11 @@
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
 @Composable
 internal fun ThreePaneScaffoldSample() {
-    val layoutDirective = calculateStandardAdaptiveLayoutDirective(calculateWindowAdaptiveInfo())
+    val scaffoldDirective = calculateStandardPaneScaffoldDirective(calculateWindowAdaptiveInfo())
     ThreePaneScaffold(
         modifier = Modifier.fillMaxSize(),
-        layoutDirective = layoutDirective,
-        scaffoldValue = calculateThreePaneScaffoldValue(layoutDirective.maxHorizontalPartitions),
+        scaffoldDirective = scaffoldDirective,
+        scaffoldValue = calculateThreePaneScaffoldValue(scaffoldDirective.maxHorizontalPartitions),
         arrangement = ThreePaneScaffoldDefaults.ListDetailLayoutArrangement,
         secondaryPane = {
             Surface(
diff --git a/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffoldStateTest.kt b/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffoldStateTest.kt
index 2b8e76d..49dbf29 100644
--- a/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffoldStateTest.kt
+++ b/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffoldStateTest.kt
@@ -41,7 +41,7 @@
 
         composeRule.setContent {
             layoutState = rememberListDetailPaneScaffoldState(
-                layoutDirectives = MockSinglePaneLayoutDirective
+                scaffoldDirective = MockSinglePaneScaffoldDirective
             )
             canNavigateBack = layoutState.canNavigateBack()
         }
@@ -64,7 +64,7 @@
 
         composeRule.setContent {
             layoutState = rememberListDetailPaneScaffoldState(
-                layoutDirectives = MockDualPaneLayoutDirective
+                scaffoldDirective = MockDualPaneScaffoldDirective
             )
             canNavigateBack = layoutState.canNavigateBack()
         }
@@ -87,7 +87,7 @@
 
         composeRule.setContent {
             layoutState = rememberListDetailPaneScaffoldState(
-                layoutDirectives = MockSinglePaneLayoutDirective
+                scaffoldDirective = MockSinglePaneScaffoldDirective
             )
             canNavigateBack = layoutState.canNavigateBack()
         }
@@ -114,7 +114,7 @@
 
         composeRule.setContent {
             layoutState = rememberListDetailPaneScaffoldState(
-                layoutDirectives = MockDualPaneLayoutDirective,
+                scaffoldDirective = MockDualPaneScaffoldDirective,
                 initialFocusHistory = listOf(
                     ListDetailPaneScaffoldRole.List,
                     ListDetailPaneScaffoldRole.Detail,
@@ -133,7 +133,7 @@
 
         composeRule.setContent {
             layoutState = rememberListDetailPaneScaffoldState(
-                layoutDirectives = MockDualPaneLayoutDirective,
+                scaffoldDirective = MockDualPaneScaffoldDirective,
                 initialFocusHistory = listOf(
                     ListDetailPaneScaffoldRole.List,
                     ListDetailPaneScaffoldRole.Detail,
@@ -155,11 +155,11 @@
     @Test
     fun singlePaneToDualPaneLayout_enforceLayoutValueChange_cannotNavigateBack() {
         lateinit var layoutState: ListDetailPaneScaffoldState
-        val mockCurrentLayoutDirective = mutableStateOf(MockSinglePaneLayoutDirective)
+        val mockCurrentScaffoldDirective = mutableStateOf(MockSinglePaneScaffoldDirective)
 
         composeRule.setContent {
             layoutState = rememberListDetailPaneScaffoldState(
-                layoutDirectives = mockCurrentLayoutDirective.value,
+                scaffoldDirective = mockCurrentScaffoldDirective.value,
                 initialFocusHistory = listOf(
                     ListDetailPaneScaffoldRole.List,
                     ListDetailPaneScaffoldRole.Detail,
@@ -169,7 +169,7 @@
         composeRule.runOnIdle {
             assertThat(layoutState.layoutValue.primary).isEqualTo(PaneAdaptedValue.Expanded)
             // Switches to dual pane
-            mockCurrentLayoutDirective.value = MockDualPaneLayoutDirective
+            mockCurrentScaffoldDirective.value = MockDualPaneScaffoldDirective
         }
 
         composeRule.runOnIdle {
@@ -179,7 +179,7 @@
 }
 
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
-private val MockSinglePaneLayoutDirective = AdaptiveLayoutDirective(
+private val MockSinglePaneScaffoldDirective = PaneScaffoldDirective(
     maxHorizontalPartitions = 1,
     gutterSizes = GutterSizes(0.dp, 0.dp),
     maxVerticalPartitions = 1,
@@ -187,7 +187,7 @@
 )
 
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
-private val MockDualPaneLayoutDirective = AdaptiveLayoutDirective(
+private val MockDualPaneScaffoldDirective = PaneScaffoldDirective(
     maxHorizontalPartitions = 2,
     gutterSizes = GutterSizes(16.dp, 16.dp),
     maxVerticalPartitions = 1,
diff --git a/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/SupportingPaneScaffoldStateTest.kt b/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/SupportingPaneScaffoldStateTest.kt
index 894e528..6e21d9e 100644
--- a/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/SupportingPaneScaffoldStateTest.kt
+++ b/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/SupportingPaneScaffoldStateTest.kt
@@ -41,7 +41,7 @@
 
         composeRule.setContent {
             layoutState = rememberSupportingPaneScaffoldState(
-                layoutDirectives = MockSinglePaneLayoutDirective
+                scaffoldDirective = MockSinglePaneScaffoldDirective
             )
             canNavigateBack = layoutState.canNavigateBack()
         }
@@ -64,7 +64,7 @@
 
         composeRule.setContent {
             layoutState = rememberSupportingPaneScaffoldState(
-                layoutDirectives = MockDualPaneLayoutDirective
+                scaffoldDirective = MockDualPaneScaffoldDirective
             )
             canNavigateBack = layoutState.canNavigateBack()
         }
@@ -87,7 +87,7 @@
 
         composeRule.setContent {
             layoutState = rememberSupportingPaneScaffoldState(
-                layoutDirectives = MockSinglePaneLayoutDirective
+                scaffoldDirective = MockSinglePaneScaffoldDirective
             )
             canNavigateBack = layoutState.canNavigateBack()
         }
@@ -114,7 +114,7 @@
 
         composeRule.setContent {
             layoutState = rememberSupportingPaneScaffoldState(
-                layoutDirectives = MockDualPaneLayoutDirective,
+                scaffoldDirective = MockDualPaneScaffoldDirective,
                 initialFocusHistory = listOf(
                     SupportingPaneScaffoldRole.Supporting,
                     SupportingPaneScaffoldRole.Main,
@@ -133,7 +133,7 @@
 
         composeRule.setContent {
             layoutState = rememberSupportingPaneScaffoldState(
-                layoutDirectives = MockDualPaneLayoutDirective,
+                scaffoldDirective = MockDualPaneScaffoldDirective,
                 initialFocusHistory = listOf(
                     SupportingPaneScaffoldRole.Supporting,
                     SupportingPaneScaffoldRole.Main,
@@ -155,11 +155,11 @@
     @Test
     fun singlePaneToDualPaneLayout_enforceLayoutValueChange_cannotNavigateBack() {
         lateinit var layoutState: SupportingPaneScaffoldState
-        val mockCurrentLayoutDirective = mutableStateOf(MockSinglePaneLayoutDirective)
+        val mockCurrentScaffoldDirective = mutableStateOf(MockSinglePaneScaffoldDirective)
 
         composeRule.setContent {
             layoutState = rememberSupportingPaneScaffoldState(
-                layoutDirectives = mockCurrentLayoutDirective.value,
+                scaffoldDirective = mockCurrentScaffoldDirective.value,
                 initialFocusHistory = listOf(
                     SupportingPaneScaffoldRole.Supporting,
                     SupportingPaneScaffoldRole.Main,
@@ -169,7 +169,7 @@
         composeRule.runOnIdle {
             assertThat(layoutState.layoutValue.primary).isEqualTo(PaneAdaptedValue.Expanded)
             // Switches to dual pane
-            mockCurrentLayoutDirective.value = MockDualPaneLayoutDirective
+            mockCurrentScaffoldDirective.value = MockDualPaneScaffoldDirective
         }
 
         composeRule.runOnIdle {
@@ -179,7 +179,7 @@
 }
 
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
-private val MockSinglePaneLayoutDirective = AdaptiveLayoutDirective(
+private val MockSinglePaneScaffoldDirective = PaneScaffoldDirective(
     maxHorizontalPartitions = 1,
     gutterSizes = GutterSizes(0.dp, 0.dp),
     maxVerticalPartitions = 1,
@@ -187,7 +187,7 @@
 )
 
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
-private val MockDualPaneLayoutDirective = AdaptiveLayoutDirective(
+private val MockDualPaneScaffoldDirective = PaneScaffoldDirective(
     maxHorizontalPartitions = 2,
     gutterSizes = GutterSizes(16.dp, 16.dp),
     maxVerticalPartitions = 1,
diff --git a/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldScreenshotTest.kt b/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldScreenshotTest.kt
index 7ff97c2..c5793d7 100644
--- a/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldScreenshotTest.kt
+++ b/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldScreenshotTest.kt
@@ -43,14 +43,14 @@
     @Test
     fun threePaneScaffold_listDetailArrangement_standard() {
         rule.setContent {
-            val layoutDirective = calculateStandardAdaptiveLayoutDirective(
+            val scaffoldDirective = calculateStandardPaneScaffoldDirective(
                 calculateWindowAdaptiveInfo()
             )
             val scaffoldValue = calculateThreePaneScaffoldValue(
-                layoutDirective.maxHorizontalPartitions
+                scaffoldDirective.maxHorizontalPartitions
             )
             SampleThreePaneScaffold(
-                layoutDirective,
+                scaffoldDirective,
                 scaffoldValue,
                 ThreePaneScaffoldDefaults.ListDetailLayoutArrangement
             )
@@ -64,14 +64,14 @@
     @Test
     fun threePaneScaffold_listDetailArrangement_dense() {
         rule.setContent {
-            val layoutDirective = calculateDenseAdaptiveLayoutDirective(
+            val scaffoldDirective = calculateDensePaneScaffoldDirective(
                 calculateWindowAdaptiveInfo()
             )
             val scaffoldValue = calculateThreePaneScaffoldValue(
-                layoutDirective.maxHorizontalPartitions
+                scaffoldDirective.maxHorizontalPartitions
             )
             SampleThreePaneScaffold(
-                layoutDirective,
+                scaffoldDirective,
                 scaffoldValue,
                 ThreePaneScaffoldDefaults.ListDetailLayoutArrangement
             )
diff --git a/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldTest.kt b/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldTest.kt
index 4b175bf..54b5ecf 100644
--- a/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldTest.kt
+++ b/compose/material3/material3-adaptive/src/androidInstrumentedTest/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffoldTest.kt
@@ -104,7 +104,7 @@
 }
 
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
-private val MockLayoutDirective = AdaptiveLayoutDirective(
+private val MockScaffoldDirective = PaneScaffoldDirective(
     maxHorizontalPartitions = 1,
     gutterSizes = GutterSizes(0.dp, 0.dp),
     maxVerticalPartitions = 1,
@@ -117,7 +117,7 @@
 @Composable
 private fun SampleThreePaneScaffold(scaffoldValue: ThreePaneScaffoldValue) {
     SampleThreePaneScaffold(
-        MockLayoutDirective,
+        MockScaffoldDirective,
         scaffoldValue,
         ThreePaneScaffoldDefaults.ListDetailLayoutArrangement
     )
@@ -126,13 +126,13 @@
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
 @Composable
 internal fun SampleThreePaneScaffold(
-    layoutDirective: AdaptiveLayoutDirective,
+    scaffoldDirective: PaneScaffoldDirective,
     scaffoldValue: ThreePaneScaffoldValue,
     arrangement: ThreePaneScaffoldArrangement
 ) {
     ThreePaneScaffold(
         modifier = Modifier.fillMaxSize().testTag(ThreePaneScaffoldTestTag),
-        layoutDirective = layoutDirective,
+        scaffoldDirective = scaffoldDirective,
         scaffoldValue = scaffoldValue,
         arrangement = arrangement,
         secondaryPane = {
diff --git a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffold.kt b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffold.kt
index bc93c71..4ac47a5 100644
--- a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffold.kt
+++ b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffold.kt
@@ -45,7 +45,7 @@
 ) {
     ThreePaneScaffold(
         modifier = modifier.fillMaxSize(),
-        layoutDirective = layoutState.layoutDirective,
+        scaffoldDirective = layoutState.scaffoldDirective,
         scaffoldValue = layoutState.layoutValue,
         arrangement = ThreePaneScaffoldDefaults.ListDetailLayoutArrangement,
         secondaryPane = listPane,
@@ -86,7 +86,7 @@
  * which works independently from any navigation frameworks. Developers can also integrate with
  * other navigation frameworks by implementing this interface.
  *
- * @property layoutDirective the current layout directives that the associated
+ * @property scaffoldDirective the current layout directives that the associated
  *           [ListDetailPaneScaffold] needs to follow. It's supposed to be automatically updated
  *           when the window configuration changes.
  * @property layoutValue the current layout value of the associated [ListDetailPaneScaffold], which
@@ -95,7 +95,7 @@
 @ExperimentalMaterial3AdaptiveApi
 @Stable
 interface ListDetailPaneScaffoldState {
-    val layoutDirective: AdaptiveLayoutDirective
+    val scaffoldDirective: PaneScaffoldDirective
     val layoutValue: ThreePaneScaffoldValue
 
     /**
@@ -124,7 +124,7 @@
 private class DefaultListDetailPaneScaffoldState(
     val internalState: DefaultThreePaneScaffoldState
 ) : ListDetailPaneScaffoldState {
-    override val layoutDirective get() = internalState.layoutDirective
+    override val scaffoldDirective get() = internalState.scaffoldDirective
     override val layoutValue get() = internalState.layoutValue
 
     override fun navigateTo(pane: ListDetailPaneScaffoldRole) {
@@ -144,8 +144,8 @@
  * used independently from any navigation frameworks and it will address the navigation purely
  * inside the [ListDetailPaneScaffold].
  *
- * @param layoutDirectives the current layout directives to follow. The default value will be
- *        Calculated with [calculateStandardAdaptiveLayoutDirective] using [WindowAdaptiveInfo]
+ * @param scaffoldDirective the current layout directives to follow. The default value will be
+ *        Calculated with [calculateStandardPaneScaffoldDirective] using [WindowAdaptiveInfo]
  *        retrieved from the current context.
  * @param adaptStrategies adaptation strategies of each pane.
  * @param initialFocusHistory the initial focus history of the scaffold, by default it will be just
@@ -154,14 +154,14 @@
 @ExperimentalMaterial3AdaptiveApi
 @Composable
 fun rememberListDetailPaneScaffoldState(
-    layoutDirectives: AdaptiveLayoutDirective =
-        calculateStandardAdaptiveLayoutDirective(calculateWindowAdaptiveInfo()),
+    scaffoldDirective: PaneScaffoldDirective =
+        calculateStandardPaneScaffoldDirective(calculateWindowAdaptiveInfo()),
     adaptStrategies: ThreePaneScaffoldAdaptStrategies =
         ListDetailPaneScaffoldDefaults.adaptStrategies(),
     initialFocusHistory: List<ListDetailPaneScaffoldRole> = listOf(ListDetailPaneScaffoldRole.List)
 ): ListDetailPaneScaffoldState {
     val internalState = rememberDefaultThreePaneScaffoldState(
-        layoutDirectives,
+        scaffoldDirective,
         adaptStrategies,
         initialFocusHistory.fastMap { it.threePaneScaffoldRole }
     )
diff --git a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/SupportingPaneScaffold.kt b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/SupportingPaneScaffold.kt
index 64eb93b8..33997bf 100644
--- a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/SupportingPaneScaffold.kt
+++ b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/SupportingPaneScaffold.kt
@@ -30,7 +30,7 @@
 ) {
     ThreePaneScaffold(
         modifier = modifier.fillMaxSize(),
-        layoutDirective = scaffoldState.layoutDirective,
+        scaffoldDirective = scaffoldState.scaffoldDirective,
         scaffoldValue = scaffoldState.layoutValue,
         arrangement = ThreePaneScaffoldDefaults.SupportingPaneLayoutArrangement,
         secondaryPane = supportingPane,
@@ -71,7 +71,7 @@
  * which works independently from any navigation frameworks. Developers can also integrate with
  * other navigation frameworks by implementing this interface.
  *
- * @property layoutDirective the current layout directives that the associated
+ * @property scaffoldDirective the current layout directives that the associated
  *           [SupportingPaneScaffold] needs to follow. It's supposed to be automatically updated
  *           when the window configuration changes.
  * @property layoutValue the current layout value of the associated [SupportingPaneScaffold], which
@@ -80,7 +80,7 @@
 @ExperimentalMaterial3AdaptiveApi
 @Stable
 interface SupportingPaneScaffoldState {
-    val layoutDirective: AdaptiveLayoutDirective
+    val scaffoldDirective: PaneScaffoldDirective
     val layoutValue: ThreePaneScaffoldValue
 
     /**
@@ -109,7 +109,7 @@
 private class DefaultSupportingPaneScaffoldState(
     val internalState: DefaultThreePaneScaffoldState
 ) : SupportingPaneScaffoldState {
-    override val layoutDirective get() = internalState.layoutDirective
+    override val scaffoldDirective get() = internalState.scaffoldDirective
     override val layoutValue get() = internalState.layoutValue
 
     override fun navigateTo(pane: SupportingPaneScaffoldRole) {
@@ -129,8 +129,8 @@
  * used independently from any navigation frameworks and it will address the navigation purely
  * inside the [SupportingPaneScaffold].
  *
- * @param layoutDirectives the current layout directives to follow. The default value will be
- *        Calculated with [calculateStandardAdaptiveLayoutDirective] using [WindowAdaptiveInfo]
+ * @param scaffoldDirective the current layout directives to follow. The default value will be
+ *        Calculated with [calculateStandardPaneScaffoldDirective] using [WindowAdaptiveInfo]
  *        retrieved from the current context.
  * @param adaptStrategies adaptation strategies of each pane.
  * @param initialFocusHistory the initial focus history of the scaffold, by default it will be just
@@ -139,14 +139,14 @@
 @ExperimentalMaterial3AdaptiveApi
 @Composable
 fun rememberSupportingPaneScaffoldState(
-    layoutDirectives: AdaptiveLayoutDirective =
-        calculateStandardAdaptiveLayoutDirective(calculateWindowAdaptiveInfo()),
+    scaffoldDirective: PaneScaffoldDirective =
+        calculateStandardPaneScaffoldDirective(calculateWindowAdaptiveInfo()),
     adaptStrategies: ThreePaneScaffoldAdaptStrategies =
         SupportingPaneScaffoldDefaults.adaptStrategies(),
     initialFocusHistory: List<SupportingPaneScaffoldRole> = listOf(SupportingPaneScaffoldRole.Main)
 ): SupportingPaneScaffoldState {
     val internalState = rememberDefaultThreePaneScaffoldState(
-        layoutDirectives,
+        scaffoldDirective,
         adaptStrategies,
         initialFocusHistory.fastMap { it.threePaneScaffoldRole }
     )
diff --git a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffold.android.kt b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffold.android.kt
index 0175dc06..c047f2d 100644
--- a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffold.android.kt
+++ b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffold.android.kt
@@ -12,7 +12,7 @@
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
 internal class DefaultThreePaneScaffoldState(
     initialFocusHistory: List<ThreePaneScaffoldRole>,
-    initialLayoutDirective: AdaptiveLayoutDirective,
+    initialScaffoldDirective: PaneScaffoldDirective,
     initialAdaptStrategies: ThreePaneScaffoldAdaptStrategies,
 ) {
 
@@ -20,7 +20,7 @@
         addAll(initialFocusHistory)
     }
 
-    var layoutDirective by mutableStateOf(initialLayoutDirective)
+    var scaffoldDirective by mutableStateOf(initialScaffoldDirective)
     var adaptStrategies by mutableStateOf(initialAdaptStrategies)
 
     val currentFocus: ThreePaneScaffoldRole?
@@ -69,7 +69,7 @@
         focus: ThreePaneScaffoldRole?
     ): ThreePaneScaffoldValue =
         calculateThreePaneScaffoldValue(
-            layoutDirective.maxHorizontalPartitions,
+            scaffoldDirective.maxHorizontalPartitions,
             adaptStrategies,
             focus
         )
@@ -79,7 +79,7 @@
          * To keep focus history saved
          */
         fun saver(
-            initialLayoutDirective: AdaptiveLayoutDirective,
+            initialScaffoldDirective: PaneScaffoldDirective,
             initialAdaptStrategies: ThreePaneScaffoldAdaptStrategies
         ): Saver<DefaultThreePaneScaffoldState, *> = listSaver(
             save = {
@@ -88,7 +88,7 @@
             restore = {
                 DefaultThreePaneScaffoldState(
                     initialFocusHistory = it,
-                    initialLayoutDirective = initialLayoutDirective,
+                    initialScaffoldDirective = initialScaffoldDirective,
                     initialAdaptStrategies = initialAdaptStrategies
                 )
             }
@@ -99,22 +99,22 @@
 @ExperimentalMaterial3AdaptiveApi
 @Composable
 internal fun rememberDefaultThreePaneScaffoldState(
-    layoutDirectives: AdaptiveLayoutDirective,
+    scaffoldDirective: PaneScaffoldDirective,
     adaptStrategies: ThreePaneScaffoldAdaptStrategies,
     initialFocusHistory: List<ThreePaneScaffoldRole>
 ): DefaultThreePaneScaffoldState =
     rememberSaveable(
         saver = DefaultThreePaneScaffoldState.saver(
-            layoutDirectives,
+            scaffoldDirective,
             adaptStrategies,
         )
     ) {
         DefaultThreePaneScaffoldState(
             initialFocusHistory = initialFocusHistory,
-            initialLayoutDirective = layoutDirectives,
+            initialScaffoldDirective = scaffoldDirective,
             initialAdaptStrategies = adaptStrategies
         )
     }.apply {
-        this.layoutDirective = layoutDirectives
+        this.scaffoldDirective = scaffoldDirective
         this.adaptStrategies = adaptStrategies
     }
diff --git a/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirectiveTest.kt b/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirectiveTest.kt
deleted file mode 100644
index 63a9db7..0000000
--- a/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirectiveTest.kt
+++ /dev/null
@@ -1,317 +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.compose.material3.adaptive
-
-import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
-import androidx.compose.material3.windowsizeclass.WindowSizeClass
-import androidx.compose.ui.geometry.Rect
-import androidx.compose.ui.unit.DpSize
-import androidx.compose.ui.unit.dp
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@OptIn(ExperimentalMaterial3AdaptiveApi::class, ExperimentalMaterial3WindowSizeClassApi::class)
-@RunWith(JUnit4::class)
-class AdaptiveLayoutDirectiveTest {
-    @Test
-    fun test_calculateStandardAdaptiveLayoutDirective_compactWidth() {
-        val layoutDirective = calculateStandardAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(400.dp, 800.dp)),
-                Posture()
-            )
-        )
-
-        assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(16.dp)
-        assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
-        assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(16.dp)
-        assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
-    }
-
-    @Test
-    fun test_calculateStandardAdaptiveLayoutDirective_mediumWidth() {
-        val layoutDirective = calculateStandardAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(750.dp, 900.dp)),
-                Posture()
-            )
-        )
-
-        assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
-        assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
-    }
-
-    @Test
-    fun test_calculateStandardAdaptiveLayoutDirective_expandedWidth() {
-        val layoutDirective = calculateStandardAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(1200.dp, 800.dp)),
-                Posture()
-            )
-        )
-
-        assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(2)
-        assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
-    }
-
-    @Test
-    fun test_calculateStandardAdaptiveLayoutDirective_tabletop() {
-        val layoutDirective = calculateStandardAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
-                Posture(isTabletop = true)
-            )
-        )
-
-        assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(2)
-        assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
-        assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(24.dp)
-    }
-
-    @Test
-    fun test_calculateDenseAdaptiveLayoutDirective_compactWidth() {
-        val layoutDirective = calculateDenseAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(400.dp, 800.dp)),
-                Posture()
-            )
-        )
-
-        assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(16.dp)
-        assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
-        assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(16.dp)
-        assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
-    }
-
-    @Test
-    fun test_calculateDenseAdaptiveLayoutDirective_mediumWidth() {
-        val layoutDirective = calculateDenseAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(750.dp, 900.dp)),
-                Posture()
-            )
-        )
-
-        assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(2)
-        assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
-    }
-
-    @Test
-    fun test_calculateDenseAdaptiveLayoutDirective_expandedWidth() {
-        val layoutDirective = calculateDenseAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(1200.dp, 800.dp)),
-                Posture()
-            )
-        )
-
-        assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(2)
-        assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(1)
-        assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
-    }
-
-    @Test
-    fun test_calculateDenseAdaptiveLayoutDirective_tabletop() {
-        val layoutDirective = calculateDenseAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
-                Posture(isTabletop = true)
-            )
-        )
-
-        assertThat(layoutDirective.maxHorizontalPartitions).isEqualTo(2)
-        assertThat(layoutDirective.maxVerticalPartitions).isEqualTo(2)
-        assertThat(layoutDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
-        assertThat(layoutDirective.gutterSizes.innerHorizontal).isEqualTo(24.dp)
-    }
-
-    @Test
-    fun test_calculateStandardAdaptiveLayoutDirective_alwaysAvoidHinge() {
-        val occludingHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-        )
-        val allHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-            Rect(2F, 2F, 3F, 3F)
-        )
-        val layoutDirective = calculateStandardAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
-                Posture(
-                    allHingeBounds = allHingeBounds,
-                    occludingHingeBounds = occludingHingeBounds
-                )
-            ),
-            HingePolicy.AlwaysAvoid
-        )
-
-        assertThat(layoutDirective.excludedBounds).isEqualTo(allHingeBounds)
-    }
-
-    @Test
-    fun test_calculateStandardAdaptiveLayoutDirective_avoidOccludingHinge() {
-        val occludingHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-        )
-        val allHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-            Rect(2F, 2F, 3F, 3F)
-        )
-        val layoutDirective = calculateStandardAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
-                Posture(
-                    allHingeBounds = allHingeBounds,
-                    occludingHingeBounds = occludingHingeBounds
-                )
-            ),
-            HingePolicy.AvoidOccluding
-        )
-
-        assertThat(layoutDirective.excludedBounds).isEqualTo(occludingHingeBounds)
-    }
-
-    @Test
-    fun test_calculateStandardAdaptiveLayoutDirective_neverAvoidHinge() {
-        val occludingHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-        )
-        val allHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-            Rect(2F, 2F, 3F, 3F)
-        )
-        val layoutDirective = calculateStandardAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
-                Posture(
-                    allHingeBounds = allHingeBounds,
-                    occludingHingeBounds = occludingHingeBounds
-                )
-            ),
-            HingePolicy.NeverAvoid
-        )
-
-        assertThat(layoutDirective.excludedBounds).isEmpty()
-    }
-
-    @Test
-    fun test_calculateDenseAdaptiveLayoutDirective_alwaysAvoidHinge() {
-        val occludingHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-        )
-        val allHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-            Rect(2F, 2F, 3F, 3F)
-        )
-        val layoutDirective = calculateDenseAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
-                Posture(
-                    allHingeBounds = allHingeBounds,
-                    occludingHingeBounds = occludingHingeBounds
-                )
-            ),
-            HingePolicy.AlwaysAvoid
-        )
-
-        assertThat(layoutDirective.excludedBounds).isEqualTo(allHingeBounds)
-    }
-
-    @Test
-    fun test_calculateDenseAdaptiveLayoutDirective_avoidOccludingHinge() {
-        val occludingHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-        )
-        val allHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-            Rect(2F, 2F, 3F, 3F)
-        )
-        val layoutDirective = calculateDenseAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
-                Posture(
-                    allHingeBounds = allHingeBounds,
-                    occludingHingeBounds = occludingHingeBounds
-                )
-            ),
-            HingePolicy.AvoidOccluding
-        )
-
-        assertThat(layoutDirective.excludedBounds).isEqualTo(occludingHingeBounds)
-    }
-
-    @Test
-    fun test_calculateDenseAdaptiveLayoutDirective_neverAvoidHinge() {
-        val occludingHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-        )
-        val allHingeBounds = listOf(
-            Rect(0F, 0F, 1F, 1F),
-            Rect(1F, 1F, 2F, 2F),
-            Rect(2F, 2F, 3F, 3F)
-        )
-        val layoutDirective = calculateDenseAdaptiveLayoutDirective(
-            WindowAdaptiveInfo(
-                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
-                Posture(
-                    allHingeBounds = allHingeBounds,
-                    occludingHingeBounds = occludingHingeBounds
-                )
-            ),
-            HingePolicy.NeverAvoid
-        )
-
-        assertThat(layoutDirective.excludedBounds).isEmpty()
-    }
-}
diff --git a/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffoldTest.kt b/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffoldTest.kt
index 359f940..6ab65eb 100644
--- a/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffoldTest.kt
+++ b/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffoldTest.kt
@@ -81,7 +81,7 @@
             )
 
         assertThat(NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
-            .isEqualTo(NavigationSuiteType.NavigationBar)
+            .isEqualTo(NavigationSuiteType.NavigationRail)
     }
 
     @Test
@@ -92,7 +92,7 @@
             )
 
         assertThat(NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
-            .isEqualTo(NavigationSuiteType.NavigationBar)
+            .isEqualTo(NavigationSuiteType.NavigationRail)
     }
 
     @Test
diff --git a/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/PaneScaffoldDirectiveTest.kt b/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/PaneScaffoldDirectiveTest.kt
new file mode 100644
index 0000000..68c5553
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/androidUnitTest/kotlin/androidx/compose/material3/adaptive/PaneScaffoldDirectiveTest.kt
@@ -0,0 +1,317 @@
+/*
+ * 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.material3.adaptive
+
+import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
+import androidx.compose.material3.windowsizeclass.WindowSizeClass
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class, ExperimentalMaterial3WindowSizeClassApi::class)
+@RunWith(JUnit4::class)
+class PaneScaffoldDirectiveTest {
+    @Test
+    fun test_calculateStandardPaneScaffoldDirective_compactWidth() {
+        val scaffoldDirective = calculateStandardPaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(400.dp, 800.dp)),
+                Posture()
+            )
+        )
+
+        assertThat(scaffoldDirective.maxHorizontalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.maxVerticalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.gutterSizes.outerVertical).isEqualTo(16.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
+        assertThat(scaffoldDirective.gutterSizes.outerHorizontal).isEqualTo(16.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+    }
+
+    @Test
+    fun test_calculateStandardPaneScaffoldDirective_mediumWidth() {
+        val scaffoldDirective = calculateStandardPaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(750.dp, 900.dp)),
+                Posture()
+            )
+        )
+
+        assertThat(scaffoldDirective.maxHorizontalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.maxVerticalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
+        assertThat(scaffoldDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+    }
+
+    @Test
+    fun test_calculateStandardPaneScaffoldDirective_expandedWidth() {
+        val scaffoldDirective = calculateStandardPaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(1200.dp, 800.dp)),
+                Posture()
+            )
+        )
+
+        assertThat(scaffoldDirective.maxHorizontalPartitions).isEqualTo(2)
+        assertThat(scaffoldDirective.maxVerticalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+    }
+
+    @Test
+    fun test_calculateStandardPaneScaffoldDirective_tabletop() {
+        val scaffoldDirective = calculateStandardPaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+                Posture(isTabletop = true)
+            )
+        )
+
+        assertThat(scaffoldDirective.maxHorizontalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.maxVerticalPartitions).isEqualTo(2)
+        assertThat(scaffoldDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
+        assertThat(scaffoldDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerHorizontal).isEqualTo(24.dp)
+    }
+
+    @Test
+    fun test_calculateDensePaneScaffoldDirective_compactWidth() {
+        val scaffoldDirective = calculateDensePaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(400.dp, 800.dp)),
+                Posture()
+            )
+        )
+
+        assertThat(scaffoldDirective.maxHorizontalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.maxVerticalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.gutterSizes.outerVertical).isEqualTo(16.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerVertical).isEqualTo(0.dp)
+        assertThat(scaffoldDirective.gutterSizes.outerHorizontal).isEqualTo(16.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+    }
+
+    @Test
+    fun test_calculateDensePaneScaffoldDirective_mediumWidth() {
+        val scaffoldDirective = calculateDensePaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(750.dp, 900.dp)),
+                Posture()
+            )
+        )
+
+        assertThat(scaffoldDirective.maxHorizontalPartitions).isEqualTo(2)
+        assertThat(scaffoldDirective.maxVerticalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+    }
+
+    @Test
+    fun test_calculateDensePaneScaffoldDirective_expandedWidth() {
+        val scaffoldDirective = calculateDensePaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(1200.dp, 800.dp)),
+                Posture()
+            )
+        )
+
+        assertThat(scaffoldDirective.maxHorizontalPartitions).isEqualTo(2)
+        assertThat(scaffoldDirective.maxVerticalPartitions).isEqualTo(1)
+        assertThat(scaffoldDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerHorizontal).isEqualTo(0.dp)
+    }
+
+    @Test
+    fun test_calculateDensePaneScaffoldDirective_tabletop() {
+        val scaffoldDirective = calculateDensePaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+                Posture(isTabletop = true)
+            )
+        )
+
+        assertThat(scaffoldDirective.maxHorizontalPartitions).isEqualTo(2)
+        assertThat(scaffoldDirective.maxVerticalPartitions).isEqualTo(2)
+        assertThat(scaffoldDirective.gutterSizes.outerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerVertical).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.outerHorizontal).isEqualTo(24.dp)
+        assertThat(scaffoldDirective.gutterSizes.innerHorizontal).isEqualTo(24.dp)
+    }
+
+    @Test
+    fun test_calculateStandardPaneScaffoldDirective_alwaysAvoidHinge() {
+        val occludingHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+        )
+        val allHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+            Rect(2F, 2F, 3F, 3F)
+        )
+        val scaffoldDirective = calculateStandardPaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+                Posture(
+                    allHingeBounds = allHingeBounds,
+                    occludingHingeBounds = occludingHingeBounds
+                )
+            ),
+            HingePolicy.AlwaysAvoid
+        )
+
+        assertThat(scaffoldDirective.excludedBounds).isEqualTo(allHingeBounds)
+    }
+
+    @Test
+    fun test_calculateStandardPaneScaffoldDirective_avoidOccludingHinge() {
+        val occludingHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+        )
+        val allHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+            Rect(2F, 2F, 3F, 3F)
+        )
+        val scaffoldDirective = calculateStandardPaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+                Posture(
+                    allHingeBounds = allHingeBounds,
+                    occludingHingeBounds = occludingHingeBounds
+                )
+            ),
+            HingePolicy.AvoidOccluding
+        )
+
+        assertThat(scaffoldDirective.excludedBounds).isEqualTo(occludingHingeBounds)
+    }
+
+    @Test
+    fun test_calculateStandardPaneScaffoldDirective_neverAvoidHinge() {
+        val occludingHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+        )
+        val allHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+            Rect(2F, 2F, 3F, 3F)
+        )
+        val scaffoldDirective = calculateStandardPaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+                Posture(
+                    allHingeBounds = allHingeBounds,
+                    occludingHingeBounds = occludingHingeBounds
+                )
+            ),
+            HingePolicy.NeverAvoid
+        )
+
+        assertThat(scaffoldDirective.excludedBounds).isEmpty()
+    }
+
+    @Test
+    fun test_calculateDensePaneScaffoldDirective_alwaysAvoidHinge() {
+        val occludingHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+        )
+        val allHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+            Rect(2F, 2F, 3F, 3F)
+        )
+        val scaffoldDirective = calculateDensePaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+                Posture(
+                    allHingeBounds = allHingeBounds,
+                    occludingHingeBounds = occludingHingeBounds
+                )
+            ),
+            HingePolicy.AlwaysAvoid
+        )
+
+        assertThat(scaffoldDirective.excludedBounds).isEqualTo(allHingeBounds)
+    }
+
+    @Test
+    fun test_calculateDensePaneScaffoldDirective_avoidOccludingHinge() {
+        val occludingHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+        )
+        val allHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+            Rect(2F, 2F, 3F, 3F)
+        )
+        val scaffoldDirective = calculateDensePaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+                Posture(
+                    allHingeBounds = allHingeBounds,
+                    occludingHingeBounds = occludingHingeBounds
+                )
+            ),
+            HingePolicy.AvoidOccluding
+        )
+
+        assertThat(scaffoldDirective.excludedBounds).isEqualTo(occludingHingeBounds)
+    }
+
+    @Test
+    fun test_calculateDensePaneScaffoldDirective_neverAvoidHinge() {
+        val occludingHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+        )
+        val allHingeBounds = listOf(
+            Rect(0F, 0F, 1F, 1F),
+            Rect(1F, 1F, 2F, 2F),
+            Rect(2F, 2F, 3F, 3F)
+        )
+        val scaffoldDirective = calculateDensePaneScaffoldDirective(
+            WindowAdaptiveInfo(
+                WindowSizeClass.calculateFromSize(DpSize(700.dp, 800.dp)),
+                Posture(
+                    allHingeBounds = allHingeBounds,
+                    occludingHingeBounds = occludingHingeBounds
+                )
+            ),
+            HingePolicy.NeverAvoid
+        )
+
+        assertThat(scaffoldDirective.excludedBounds).isEmpty()
+    }
+}
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 0d60c95..677926b 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
@@ -43,6 +43,7 @@
 import androidx.compose.material3.contentColorFor
 import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion.Compact
 import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion.Expanded
+import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion.Medium
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.collection.MutableVector
@@ -362,7 +363,9 @@
         return with(adaptiveInfo) {
             if (posture.isTabletop || windowSizeClass.heightSizeClass == Compact) {
                 NavigationSuiteType.NavigationBar
-            } else if (windowSizeClass.widthSizeClass == Expanded) {
+            } else if (windowSizeClass.widthSizeClass == Expanded ||
+                windowSizeClass.widthSizeClass == Medium
+            ) {
                 NavigationSuiteType.NavigationRail
             } else {
                 NavigationSuiteType.NavigationBar
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirective.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffoldDirective.kt
similarity index 92%
rename from compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirective.kt
rename to compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffoldDirective.kt
index d012a95a..ca23073 100644
--- a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/AdaptiveLayoutDirective.kt
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/PaneScaffoldDirective.kt
@@ -23,7 +23,7 @@
 import androidx.compose.ui.unit.dp
 
 /**
- * Calculates the standard [AdaptiveLayoutDirective] from a given [WindowAdaptiveInfo]. Use this
+ * Calculates the standard [PaneScaffoldDirective] from a given [WindowAdaptiveInfo]. Use this
  * method with [calculateWindowAdaptiveInfo] to acquire Material-recommended adaptive layout
  * settings of the current activity window.
  *
@@ -33,14 +33,14 @@
  * @param windowAdaptiveInfo [WindowAdaptiveInfo] that collects useful information in making
  *                           layout adaptation decisions like [WindowSizeClass].
  * @param hingePolicy [HingePolicy] that decides how layouts are supposed to address hinges.
- * @return an [AdaptiveLayoutDirective] to be used to decide adaptive layout states.
+ * @return an [PaneScaffoldDirective] to be used to decide adaptive layout states.
  */
 // TODO(b/285144647): Add more details regarding the use scenarios of this function.
 @ExperimentalMaterial3AdaptiveApi
-fun calculateStandardAdaptiveLayoutDirective(
+fun calculateStandardPaneScaffoldDirective(
     windowAdaptiveInfo: WindowAdaptiveInfo,
     hingePolicy: HingePolicy = HingePolicy.AvoidSeparating
-): AdaptiveLayoutDirective {
+): PaneScaffoldDirective {
     val maxHorizontalPartitions: Int
     val gutterOuterVertical: Dp
     val gutterInnerVertical: Dp
@@ -73,7 +73,7 @@
         gutterInnerHorizontal = 0.dp
     }
 
-    return AdaptiveLayoutDirective(
+    return PaneScaffoldDirective(
         maxHorizontalPartitions,
         GutterSizes(
             gutterOuterVertical, gutterInnerVertical, innerHorizontal = gutterInnerHorizontal
@@ -84,7 +84,7 @@
 }
 
 /**
- * Calculates the dense-mode [AdaptiveLayoutDirective] from a given [WindowAdaptiveInfo]. Use this
+ * Calculates the dense-mode [PaneScaffoldDirective] from a given [WindowAdaptiveInfo]. Use this
  * method with [calculateWindowAdaptiveInfo] to acquire Material-recommended dense-mode adaptive
  * layout settings of the current activity window.
  *
@@ -94,14 +94,14 @@
  * @param windowAdaptiveInfo [WindowAdaptiveInfo] that collects useful information in making
  *                           layout adaptation decisions like [WindowSizeClass].
  * @param hingePolicy [HingePolicy] that decides how layouts are supposed to address hinges.
- * @return an [AdaptiveLayoutDirective] to be used to decide adaptive layout states.
+ * @return an [PaneScaffoldDirective] to be used to decide adaptive layout states.
  */
 // TODO(b/285144647): Add more details regarding the use scenarios of this function.
 @ExperimentalMaterial3AdaptiveApi
-fun calculateDenseAdaptiveLayoutDirective(
+fun calculateDensePaneScaffoldDirective(
     windowAdaptiveInfo: WindowAdaptiveInfo,
     hingePolicy: HingePolicy = HingePolicy.AvoidSeparating
-): AdaptiveLayoutDirective {
+): PaneScaffoldDirective {
     val maxHorizontalPartitions: Int
     val gutterOuterVertical: Dp
     val gutterInnerVertical: Dp
@@ -134,7 +134,7 @@
         gutterInnerHorizontal = 0.dp
     }
 
-    return AdaptiveLayoutDirective(
+    return PaneScaffoldDirective(
         maxHorizontalPartitions,
         GutterSizes(
             gutterOuterVertical, gutterInnerVertical, innerHorizontal = gutterInnerHorizontal
@@ -155,10 +155,10 @@
 }
 
 /**
- * Top-level directives about how an adaptive layout should be arranged and spaced, like how many
+ * Top-level directives about how a pane scaffold should be arranged and spaced, like how many
  * partitions the layout can be split into and what should be the gutter size.
  *
- * @constructor create an instance of [AdaptiveLayoutDirective]
+ * @constructor create an instance of [PaneScaffoldDirective]
  * @param maxHorizontalPartitions the max number of partitions along the horizontal axis the layout
  *        can be split into.
  * @param gutterSizes the gutter sizes between panes the layout should preserve.
@@ -169,7 +169,7 @@
  */
 @ExperimentalMaterial3AdaptiveApi
 @Immutable
-class AdaptiveLayoutDirective(
+class PaneScaffoldDirective(
     val maxHorizontalPartitions: Int,
     val gutterSizes: GutterSizes,
     val maxVerticalPartitions: Int,
@@ -177,7 +177,7 @@
 ) {
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
-        if (other !is AdaptiveLayoutDirective) return false
+        if (other !is PaneScaffoldDirective) return false
         if (maxHorizontalPartitions != other.maxHorizontalPartitions) return false
         if (gutterSizes != other.gutterSizes) return false
         if (maxVerticalPartitions != other.maxVerticalPartitions) return false
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffold.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffold.kt
index 9d35814..66b5b3a 100644
--- a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffold.kt
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/ThreePaneScaffold.kt
@@ -54,18 +54,18 @@
 /**
  * A pane scaffold composable that can display up to three panes according to the instructions
  * provided by [ThreePaneScaffoldValue] in the order that [ThreePaneScaffoldArrangement] specifies,
- * and allocate margins and spacers according to [AdaptiveLayoutDirective].
+ * and allocate margins and spacers according to [PaneScaffoldDirective].
  *
  * [ThreePaneScaffold] is the base composable functions of adaptive programming. Developers can
  * freely pipeline the relevant adaptive signals and use them as input of the scaffold function
  * to render the final adaptive layout.
  *
- * It's recommended to use [ThreePaneScaffold] with [calculateStandardAdaptiveLayoutDirective],
+ * It's recommended to use [ThreePaneScaffold] with [calculateStandardPaneScaffoldDirective],
  * [calculateThreePaneScaffoldValue] to follow the Material design guidelines on adaptive
  * programming.
  *
  * @param modifier The modifier to be applied to the layout.
- * @param layoutDirective The top-level directives about how the scaffold should arrange its panes.
+ * @param scaffoldDirective The top-level directives about how the scaffold should arrange its panes.
  * @param scaffoldValue The current adapted value of the scaffold.
  * @param arrangement The arrangement of the panes in the scaffold.
  * @param secondaryPane The content of the secondary pane that has a priority lower then the primary
@@ -77,7 +77,7 @@
 @Composable
 fun ThreePaneScaffold(
     modifier: Modifier,
-    layoutDirective: AdaptiveLayoutDirective,
+    scaffoldDirective: PaneScaffoldDirective,
     scaffoldValue: ThreePaneScaffoldValue,
     arrangement: ThreePaneScaffoldArrangement,
     secondaryPane: @Composable ThreePaneScaffoldScope.(PaneAdaptedValue) -> Unit,
@@ -146,8 +146,8 @@
     )
 
     val measurePolicy =
-        remember { ThreePaneContentMeasurePolicy(layoutDirective, scaffoldValue, arrangement) }
-    measurePolicy.layoutDirective = layoutDirective
+        remember { ThreePaneContentMeasurePolicy(scaffoldDirective, scaffoldValue, arrangement) }
+    measurePolicy.scaffoldDirective = scaffoldDirective
     measurePolicy.scaffoldValue = scaffoldValue
     measurePolicy.arrangement = arrangement
 
@@ -320,7 +320,7 @@
 
 @OptIn(ExperimentalMaterial3AdaptiveApi::class)
 private class ThreePaneContentMeasurePolicy(
-    var layoutDirective: AdaptiveLayoutDirective,
+    var scaffoldDirective: PaneScaffoldDirective,
     var scaffoldValue: ThreePaneScaffoldValue,
     var arrangement: ThreePaneScaffoldArrangement
 ) : MultiContentMeasurePolicy {
@@ -368,10 +368,10 @@
                 it == PaneAdaptedValue.Hidden
             }
 
-            val outerVerticalGutterSize = layoutDirective.gutterSizes.outerVertical.roundToPx()
-            val innerVerticalGutterSize = layoutDirective.gutterSizes.innerVertical.roundToPx()
+            val outerVerticalGutterSize = scaffoldDirective.gutterSizes.outerVertical.roundToPx()
+            val innerVerticalGutterSize = scaffoldDirective.gutterSizes.innerVertical.roundToPx()
             val outerHorizontalGutterSize =
-                layoutDirective.gutterSizes.outerHorizontal.roundToPx()
+                scaffoldDirective.gutterSizes.outerHorizontal.roundToPx()
             val outerBounds = IntRect(
                 outerVerticalGutterSize,
                 outerHorizontalGutterSize,
@@ -379,7 +379,7 @@
                 constraints.maxHeight - outerHorizontalGutterSize
             )
 
-            if (layoutDirective.excludedBounds.isNotEmpty()) {
+            if (scaffoldDirective.excludedBounds.isNotEmpty()) {
                 val layoutBounds = coordinates!!.boundsInWindow()
                 val layoutPhysicalPartitions = mutableListOf<Rect>()
                 var actualLeft = layoutBounds.left + outerVerticalGutterSize
@@ -387,7 +387,7 @@
                 val actualTop = layoutBounds.top + outerHorizontalGutterSize
                 val actualBottom = layoutBounds.bottom - outerHorizontalGutterSize
                 // Assume hinge bounds are sorted from left to right, non-overlapped.
-                layoutDirective.excludedBounds.fastForEach { hingeBound ->
+                scaffoldDirective.excludedBounds.fastForEach { hingeBound ->
                     if (hingeBound.left <= actualLeft) {
                         // The hinge is at the left of the layout, adjust the left edge of
                         // the current partition to the actual displayable bounds.
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt
index b83db8b..c22169b 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt
@@ -131,7 +131,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = LinearAnimationDuration
-                0f at FirstLineHeadDelay with FirstLineHeadEasing
+                0f at FirstLineHeadDelay using FirstLineHeadEasing
                 1f at FirstLineHeadDuration + FirstLineHeadDelay
             }
         )
@@ -142,7 +142,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = LinearAnimationDuration
-                0f at FirstLineTailDelay with FirstLineTailEasing
+                0f at FirstLineTailDelay using FirstLineTailEasing
                 1f at FirstLineTailDuration + FirstLineTailDelay
             }
         )
@@ -153,7 +153,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = LinearAnimationDuration
-                0f at SecondLineHeadDelay with SecondLineHeadEasing
+                0f at SecondLineHeadDelay using SecondLineHeadEasing
                 1f at SecondLineHeadDuration + SecondLineHeadDelay
             }
         )
@@ -164,7 +164,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = LinearAnimationDuration
-                0f at SecondLineTailDelay with SecondLineTailEasing
+                0f at SecondLineTailDelay using SecondLineTailEasing
                 1f at SecondLineTailDuration + SecondLineTailDelay
             }
         )
@@ -431,7 +431,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = HeadAndTailAnimationDuration + HeadAndTailDelayDuration
-                0f at 0 with CircularEasing
+                0f at 0 using CircularEasing
                 JumpRotationAngle at HeadAndTailAnimationDuration
             }
         )
@@ -442,7 +442,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = HeadAndTailAnimationDuration + HeadAndTailDelayDuration
-                0f at HeadAndTailDelayDuration with CircularEasing
+                0f at HeadAndTailDelayDuration using CircularEasing
                 JumpRotationAngle at durationMillis
             }
         )
diff --git a/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetector.kt b/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetector.kt
index 5c7e102..6911407 100644
--- a/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetector.kt
+++ b/compose/ui/ui-lint/src/main/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetector.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.lint.Names
 import androidx.compose.lint.Package
-import androidx.compose.lint.PackageName
 import androidx.compose.lint.isInPackageName
 import com.android.tools.lint.detector.api.Category
 import com.android.tools.lint.detector.api.Detector
@@ -35,6 +34,7 @@
 import org.jetbrains.uast.UElement
 import org.jetbrains.uast.UMethod
 import org.jetbrains.uast.kotlin.KotlinUFunctionCallExpression
+import org.jetbrains.uast.kotlin.KotlinULambdaExpression
 
 @Suppress("UnstableApiUsage")
 class SuspiciousCompositionLocalModifierReadDetector : Detector(), SourceCodeScanner {
@@ -46,10 +46,11 @@
 
     override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
         if (!method.isInPackageName(Names.Ui.Node.PackageName)) return
-        reportIfAnyParentIsNodeLifecycleCallback(context, node, node)
+        reportIfInNodeLifecycleCallback(context, node, node)
+        reportIfInLazyBlock(context, node, node)
     }
 
-    private tailrec fun reportIfAnyParentIsNodeLifecycleCallback(
+    private tailrec fun reportIfInNodeLifecycleCallback(
         context: JavaContext,
         node: UElement?,
         usage: UCallExpression
@@ -75,6 +76,20 @@
                 }
             }
             return
+        } else if (node is KotlinULambdaExpression.Body) {
+            return
+        }
+
+        reportIfInNodeLifecycleCallback(context, node.uastParent, usage)
+    }
+
+    private tailrec fun reportIfInLazyBlock(
+        context: JavaContext,
+        node: UElement?,
+        usage: UCallExpression
+    ) {
+        if (node == null) {
+            return
         } else if (node is KotlinUFunctionCallExpression && node.isLazyDelegate()) {
             report(context, usage) { localBeingRead ->
                 "Reading $localBeingRead lazily will only access the CompositionLocal's value " +
@@ -84,7 +99,7 @@
             return
         }
 
-        reportIfAnyParentIsNodeLifecycleCallback(context, node.uastParent, usage)
+        reportIfInLazyBlock(context, node.uastParent, usage)
     }
 
     private inline fun report(
diff --git a/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetectorTest.kt b/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetectorTest.kt
index 8a8bc0d..6bd0907 100644
--- a/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetectorTest.kt
+++ b/compose/ui/ui-lint/src/test/java/androidx/compose/ui/lint/SuspiciousCompositionLocalModifierReadDetectorTest.kt
@@ -133,6 +133,46 @@
     }
 
     @Test
+    fun testCompositionLocalReadInAttachDetachLambdaNotReported() {
+        lint().files(
+            kotlin(
+                """
+                package test
+
+                import androidx.compose.ui.Modifier
+                import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
+                import androidx.compose.ui.node.currentValueOf
+                import androidx.compose.runtime.CompositionLocal
+                import androidx.compose.runtime.compositionLocalOf
+                import androidx.compose.runtime.staticCompositionLocalOf
+
+                val staticLocalInt = staticCompositionLocalOf { 0 }
+                val localInt = compositionLocalOf { 0 }
+
+                class NodeUnderTest : Modifier.Node(), CompositionLocalConsumerModifierNode {
+                    override fun onAttach() {
+                        func { val readValue = currentValueOf(localInt) }
+                    }
+
+                    override fun onDetach() {
+                        func { val readValue = currentValueOf(staticLocalInt) }
+                    }
+
+                    private inline fun func(block: () -> Unit) {
+                        block()
+                    }
+                }
+            """
+            ),
+            CompositionLocalStub,
+            CompositionLocalConsumerModifierStub,
+            ModifierNodeStub
+        )
+            .run()
+            .expectClean()
+    }
+
+    @Test
     fun testCompositionLocalReadInModifierInitializer() {
         lint().files(
             kotlin(
diff --git a/compose/ui/ui-tooling-preview/api/current.txt b/compose/ui/ui-tooling-preview/api/current.txt
index e43cd20..bee1c29 100644
--- a/compose/ui/ui-tooling-preview/api/current.txt
+++ b/compose/ui/ui-tooling-preview/api/current.txt
@@ -124,7 +124,7 @@
     property public kotlin.sequences.Sequence<T> values;
   }
 
-  public final class LoremIpsum implements androidx.compose.ui.tooling.preview.PreviewParameterProvider<java.lang.String> {
+  public class LoremIpsum implements androidx.compose.ui.tooling.preview.PreviewParameterProvider<java.lang.String> {
     ctor public LoremIpsum();
     ctor public LoremIpsum(int words);
     method public kotlin.sequences.Sequence<java.lang.String> getValues();
diff --git a/compose/ui/ui-tooling-preview/api/restricted_current.txt b/compose/ui/ui-tooling-preview/api/restricted_current.txt
index e43cd20..bee1c29 100644
--- a/compose/ui/ui-tooling-preview/api/restricted_current.txt
+++ b/compose/ui/ui-tooling-preview/api/restricted_current.txt
@@ -124,7 +124,7 @@
     property public kotlin.sequences.Sequence<T> values;
   }
 
-  public final class LoremIpsum implements androidx.compose.ui.tooling.preview.PreviewParameterProvider<java.lang.String> {
+  public class LoremIpsum implements androidx.compose.ui.tooling.preview.PreviewParameterProvider<java.lang.String> {
     ctor public LoremIpsum();
     ctor public LoremIpsum(int words);
     method public kotlin.sequences.Sequence<java.lang.String> getValues();
diff --git a/compose/ui/ui-tooling-preview/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/datasource/LoremIpsum.kt b/compose/ui/ui-tooling-preview/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/datasource/LoremIpsum.kt
index a02e165..dec0f53 100644
--- a/compose/ui/ui-tooling-preview/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/datasource/LoremIpsum.kt
+++ b/compose/ui/ui-tooling-preview/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/datasource/LoremIpsum.kt
@@ -43,7 +43,7 @@
  *
  * @param words Number of words from "Lorem Ipsum" to use.
  */
-class LoremIpsum(private val words: Int) : PreviewParameterProvider<String> {
+open class LoremIpsum(private val words: Int) : PreviewParameterProvider<String> {
     // Unfortunately using default parameters seem to fail to be instantiated via reflection.
     // We can workaround it by creating the default constructor manually.
     constructor() : this(500)
diff --git a/compose/ui/ui-tooling/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/PreviewParameterTest.kt b/compose/ui/ui-tooling/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/PreviewParameterTest.kt
index 46d9006..ee8d3a72 100644
--- a/compose/ui/ui-tooling/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/PreviewParameterTest.kt
+++ b/compose/ui/ui-tooling/src/androidInstrumentedTest/kotlin/androidx/compose/ui/tooling/PreviewParameterTest.kt
@@ -118,4 +118,18 @@
             )
         }
     }
+
+    private class LoremIpsum5WordsProvider : LoremIpsum(5)
+
+    @Test
+    fun checkLoremIpsumProviderSubclass() {
+        activityTestRule.runOnUiThread {
+            composeViewAdapter.init(
+                "androidx.compose.ui.tooling.ParameterProviderComposableKt",
+                "OneStringParameter",
+                parameterProvider = LoremIpsum5WordsProvider::class.java,
+                debugViewInfos = true
+            )
+        }
+    }
 }
diff --git a/compose/ui/ui-unit/src/androidInstrumentedTest/kotlin/androidx/compose/ui/unit/fontscaling/FontScaleConverterFactoryTest.kt b/compose/ui/ui-unit/src/androidInstrumentedTest/kotlin/androidx/compose/ui/unit/fontscaling/FontScaleConverterFactoryTest.kt
index 4386510..15f7e03 100644
--- a/compose/ui/ui-unit/src/androidInstrumentedTest/kotlin/androidx/compose/ui/unit/fontscaling/FontScaleConverterFactoryTest.kt
+++ b/compose/ui/ui-unit/src/androidInstrumentedTest/kotlin/androidx/compose/ui/unit/fontscaling/FontScaleConverterFactoryTest.kt
@@ -244,7 +244,7 @@
 
     companion object {
         private const val CONVERSION_TOLERANCE = 0.05f
-        private const val INTERPOLATED_TOLERANCE = 0.2f
+        private const val INTERPOLATED_TOLERANCE = 0.3f
     }
 }
 
diff --git a/compose/ui/ui-util/src/androidUnitTest/kotlin/androidx/compose/ui/util/InlineClassHelperTest.kt b/compose/ui/ui-util/src/androidUnitTest/kotlin/androidx/compose/ui/util/InlineClassHelperTest.kt
index a254057..03ee383 100644
--- a/compose/ui/ui-util/src/androidUnitTest/kotlin/androidx/compose/ui/util/InlineClassHelperTest.kt
+++ b/compose/ui/ui-util/src/androidUnitTest/kotlin/androidx/compose/ui/util/InlineClassHelperTest.kt
@@ -23,7 +23,6 @@
 
 @RunWith(JUnit4::class)
 class InlineClassHelperTest {
-
     @Test
     fun packAndUnpackFloats() {
         val first = Float.MAX_VALUE
@@ -95,4 +94,15 @@
         assertEquals(first, unpackInt1(packed))
         assertEquals(second, unpackInt2(packed))
     }
+
+    @Test
+    fun rawBits() {
+        val first = Float.NaN
+        val second = multZero(Float.POSITIVE_INFINITY)
+        val packed = packFloats(first, second)
+        assertEquals(first.toRawBits(), unpackFloat1(packed).toRawBits())
+        assertEquals(second.toRawBits(), unpackFloat2(packed).toRawBits())
+    }
+
+    fun multZero(value: Float) = value * 0f
 }
diff --git a/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/InlineClassHelper.kt b/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/InlineClassHelper.kt
index c1548f2..710187b 100644
--- a/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/InlineClassHelper.kt
+++ b/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/InlineClassHelper.kt
@@ -22,8 +22,8 @@
  * Packs two Float values into one Long value for use in inline classes.
  */
 inline fun packFloats(val1: Float, val2: Float): Long {
-    val v1 = val1.toBits().toLong()
-    val v2 = val2.toBits().toLong()
+    val v1 = val1.toRawBits().toLong()
+    val v2 = val2.toRawBits().toLong()
     return v1.shl(32) or (v2 and 0xFFFFFFFF)
 }
 
diff --git a/compose/ui/ui-viewbinding/samples/src/androidTest/AndroidManifest.xml b/compose/ui/ui-viewbinding/samples/src/androidTest/AndroidManifest.xml
index cc8347b..c201303d 100644
--- a/compose/ui/ui-viewbinding/samples/src/androidTest/AndroidManifest.xml
+++ b/compose/ui/ui-viewbinding/samples/src/androidTest/AndroidManifest.xml
@@ -19,5 +19,6 @@
         <activity android:name="androidx.compose.ui.samples.InflatedFragmentActivity"/>
         <activity android:name="androidx.compose.ui.samples.ChildInflatedFragmentActivity"/>
         <activity android:name="androidx.compose.ui.samples.EmptyFragmentActivity"/>
+        <activity android:name="androidx.compose.ui.samples.ComposeInflatedFragmentActivity"/>
     </application>
 </manifest>
diff --git a/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/FragmentRecreateTest.kt b/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/FragmentRecreateTest.kt
index 1439a9b..5de01b8 100644
--- a/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/FragmentRecreateTest.kt
+++ b/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/FragmentRecreateTest.kt
@@ -22,6 +22,7 @@
 import androidx.activity.compose.setContent
 import androidx.compose.ui.platform.ComposeView
 import androidx.compose.ui.viewbinding.samples.R
+import androidx.compose.ui.viewbinding.samples.databinding.SampleEditTextLayoutBinding
 import androidx.compose.ui.viewbinding.samples.databinding.TestFragmentLayoutBinding
 import androidx.compose.ui.viewinterop.AndroidViewBinding
 import androidx.fragment.app.Fragment
@@ -51,6 +52,13 @@
                 supportFragmentManager.findFragmentById(R.id.fragment_container)!!
             }
             assertThat(fragment.requireView().parent).isNotNull()
+            val binding = SampleEditTextLayoutBinding.bind(fragment.requireView())
+            assertThat(binding.editText.text.toString()).isEqualTo("Default")
+
+            // Update the state to make sure it gets saved and restored properly
+            withActivity {
+                binding.editText.setText("Updated")
+            }
 
             recreate()
 
@@ -58,6 +66,9 @@
                 supportFragmentManager.findFragmentById(R.id.fragment_container)!!
             }
             assertThat(recreatedFragment.requireView().parent).isNotNull()
+            val recreatedBinding = SampleEditTextLayoutBinding.bind(
+                recreatedFragment.requireView())
+            assertThat(recreatedBinding.editText.text.toString()).isEqualTo("Updated")
         }
     }
 
@@ -72,6 +83,13 @@
             assertWithMessage("Fragment should be added as a child fragment")
                 .that(fragment).isNotNull()
             assertThat(fragment!!.requireView().parent).isNotNull()
+            val binding = SampleEditTextLayoutBinding.bind(fragment.requireView())
+            assertThat(binding.editText.text.toString()).isEqualTo("Default")
+
+            // Update the state to make sure it gets saved and restored properly
+            withActivity {
+                binding.editText.setText("Updated")
+            }
 
             recreate()
 
@@ -83,6 +101,9 @@
             assertWithMessage("Fragment should be added as a child fragment")
                 .that(recreatedFragment).isNotNull()
             assertThat(recreatedFragment!!.requireView().parent).isNotNull()
+            val recreatedBinding = SampleEditTextLayoutBinding.bind(
+                recreatedFragment.requireView())
+            assertThat(recreatedBinding.editText.text.toString()).isEqualTo("Updated")
         }
     }
 }
diff --git a/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/FragmentRemoveTest.kt b/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/FragmentRemoveTest.kt
index 443d6c3..ec98ec8 100644
--- a/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/FragmentRemoveTest.kt
+++ b/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/FragmentRemoveTest.kt
@@ -16,16 +16,29 @@
 
 package androidx.compose.ui.samples
 
+import android.os.Bundle
+import android.view.ViewGroup
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
 import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.unit.dp
 import androidx.compose.ui.viewbinding.samples.R
+import androidx.compose.ui.viewbinding.samples.databinding.SampleEditTextLayoutBinding
 import androidx.compose.ui.viewbinding.samples.databinding.TestFragmentLayoutBinding
 import androidx.compose.ui.viewinterop.AndroidViewBinding
 import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.Lifecycle
+import androidx.test.core.app.ActivityScenario
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
+import androidx.testutils.withActivity
+import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Rule
 import org.junit.Test
@@ -64,6 +77,147 @@
             .that(fragment)
             .isNull()
     }
+
+    @Test
+    fun testRemovalRemovesState() {
+        var show by mutableStateOf(true)
+
+        rule.setContent {
+            if (show) {
+                AndroidViewBinding(TestFragmentLayoutBinding::inflate)
+            }
+        }
+
+        var fragment = rule.activity.supportFragmentManager
+            .findFragmentById(R.id.fragment_container)
+        assertWithMessage("Fragment should be present when AndroidViewBinding is in the hierarchy")
+            .that(fragment)
+            .isNotNull()
+
+        var binding = SampleEditTextLayoutBinding.bind(fragment!!.requireView())
+        assertThat(binding.editText.text.toString()).isEqualTo("Default")
+
+        // Update the state to allow verifying the state is destroyed when the
+        // AndroidViewBinding is removed from composition
+        rule.runOnUiThread {
+            binding.editText.setText("Updated")
+        }
+
+        show = false
+
+        rule.waitForIdle()
+
+        fragment = rule.activity.supportFragmentManager
+            .findFragmentById(R.id.fragment_container)
+        assertWithMessage("Fragment should be removed when the AndroidViewBinding is removed")
+            .that(fragment)
+            .isNull()
+
+        show = true
+
+        rule.waitForIdle()
+
+        fragment = rule.activity.supportFragmentManager
+            .findFragmentById(R.id.fragment_container)
+        assertWithMessage("Fragment should be present when AndroidViewBinding is in the hierarchy")
+            .that(fragment)
+            .isNotNull()
+        binding = SampleEditTextLayoutBinding.bind(fragment!!.requireView())
+
+        // State should be reset back to the default
+        assertThat(binding.editText.text.toString()).isEqualTo("Default")
+    }
+
+    @Test
+    fun testRemovalRemovesStateOnBackwardWrite() {
+        var showStateA by mutableStateOf(true)
+
+        rule.setContent {
+            if (showStateA) {
+                AndroidViewBinding(TestFragmentLayoutBinding::inflate)
+            } else {
+                SideEffect {
+                    showStateA = true
+                }
+            }
+        }
+
+        var fragment = rule.activity.supportFragmentManager
+            .findFragmentById(R.id.fragment_container)
+        assertWithMessage("Fragment should be present when AndroidViewBinding is in the hierarchy")
+            .that(fragment)
+            .isNotNull()
+
+        var binding = SampleEditTextLayoutBinding.bind(fragment!!.requireView())
+        assertThat(binding.editText.text.toString()).isEqualTo("Default")
+
+        // Update the state to allow verifying the state is destroyed when the
+        // AndroidViewBinding is removed from composition
+        rule.runOnUiThread {
+            binding.editText.setText("Updated")
+        }
+
+        showStateA = false
+
+        rule.waitForIdle()
+
+        fragment = rule.activity.supportFragmentManager
+            .findFragmentById(R.id.fragment_container)
+        assertWithMessage("Fragment should be present when AndroidViewBinding is in the hierarchy")
+            .that(fragment)
+            .isNotNull()
+        binding = SampleEditTextLayoutBinding.bind(fragment!!.requireView())
+
+        // State should be reset back to the default
+        assertThat(binding.editText.text.toString()).isEqualTo("Default")
+    }
+
+    @Test
+    fun testRemovalRemovesStateOnCompositionDisposalAndRecreation() {
+        with(ActivityScenario.launch(ComposeInflatedFragmentActivity::class.java)) {
+            withActivity {
+                val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)!!
+                assertThat(fragment.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
+                val binding = SampleEditTextLayoutBinding.bind(fragment.requireView())
+                assertThat(binding.editText.text.toString()).isEqualTo("Default")
+
+                // Update the state to make sure it gets saved and restored properly
+                binding.editText.setText("Updated")
+
+                // detach - attach to dispose composition and compose it again
+                val root = composeView!!.parent as ViewGroup
+                root.removeView(composeView)
+                root.addView(composeView)
+            }
+
+            withActivity {
+                val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
+                assertThat(fragment).isNotNull()
+                assertThat(fragment!!.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED)
+                val recreatedBinding = SampleEditTextLayoutBinding.bind(
+                    fragment.requireView())
+                assertThat(recreatedBinding.editText.text.toString()).isEqualTo("Default")
+            }
+        }
+    }
 }
 
 class EmptyFragmentActivity : FragmentActivity()
+
+class ComposeInflatedFragmentActivity : FragmentActivity() {
+    var composeView: ComposeView? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContent {
+            AndroidViewBinding(
+                TestFragmentLayoutBinding::inflate,
+                Modifier.requiredSize(50.dp),
+            )
+        }
+
+        composeView = window.decorView
+            .findViewById<ViewGroup>(android.R.id.content)
+            .getChildAt(0) as? ComposeView
+    }
+}
diff --git a/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/InflatedFragment.kt b/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/InflatedFragment.kt
index e94e7fc..2b66256 100644
--- a/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/InflatedFragment.kt
+++ b/compose/ui/ui-viewbinding/samples/src/androidTest/java/androidx/compose/ui/samples/InflatedFragment.kt
@@ -19,4 +19,4 @@
 import androidx.compose.ui.viewbinding.samples.R
 import androidx.fragment.app.Fragment
 
-class InflatedFragment : Fragment(R.layout.sample_layout)
+class InflatedFragment : Fragment(R.layout.sample_edit_text_layout)
diff --git a/compose/ui/ui-viewbinding/samples/src/main/res/layout/sample_edit_text_layout.xml b/compose/ui/ui-viewbinding/samples/src/main/res/layout/sample_edit_text_layout.xml
new file mode 100644
index 0000000..97b87cd
--- /dev/null
+++ b/compose/ui/ui-viewbinding/samples/src/main/res/layout/sample_edit_text_layout.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/fragment_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <EditText
+        android:id="@+id/edit_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="Default" />
+</FrameLayout>
\ No newline at end of file
diff --git a/compose/ui/ui-viewbinding/src/main/java/androidx/compose/ui/viewinterop/AndroidViewBinding.kt b/compose/ui/ui-viewbinding/src/main/java/androidx/compose/ui/viewinterop/AndroidViewBinding.kt
index 1424583..5f2a288 100644
--- a/compose/ui/ui-viewbinding/src/main/java/androidx/compose/ui/viewinterop/AndroidViewBinding.kt
+++ b/compose/ui/ui-viewbinding/src/main/java/androidx/compose/ui/viewinterop/AndroidViewBinding.kt
@@ -31,7 +31,7 @@
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentActivity
 import androidx.fragment.app.FragmentContainerView
-import androidx.fragment.app.commit
+import androidx.fragment.app.commitNow
 import androidx.fragment.app.findFragment
 import androidx.viewbinding.ViewBinding
 
@@ -195,7 +195,7 @@
                     if (existingFragment != null && !fragmentManager.isStateSaved) {
                         // If the state isn't saved, that means that some state change
                         // has removed this Composable from the hierarchy
-                        fragmentManager.commit {
+                        fragmentManager.commitNow {
                             remove(existingFragment)
                         }
                     }
diff --git a/development/build_log_simplifier/message-flakes.ignore b/development/build_log_simplifier/message-flakes.ignore
index 6a1c68d..eb5d676 100644
--- a/development/build_log_simplifier/message-flakes.ignore
+++ b/development/build_log_simplifier/message-flakes.ignore
@@ -49,9 +49,6 @@
 \[ant\:jacocoReport\] Note\: Recompile with \-Xlint\:unchecked for details\.
 # b/179833331 , https://youtrack.jetbrains.com/issue/KT-35156
 # b/181258249 , https://youtrack.jetbrains.com/issue/KT-43881
-# > Task :jetifier-core:compileKotlin
-Could not perform incremental compilation\: Could not connect to Kotlin compile daemon
-Could not connect to kotlin daemon\. Using fallback strategy\.
 \.\.\. [0-9]+ more
 at java\.rmi\/sun\.rmi\.transport\.StreamRemoteCall\.exceptionReceivedFromServer\(StreamRemoteCall\.java\:[0-9]+\)
 at java\.rmi\/sun\.rmi\.transport\.StreamRemoteCall\.executeCall\(StreamRemoteCall\.java\:[0-9]+\)
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index 60beba3..4c2f30d 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -11,6 +11,7 @@
 Daemon will be stopped at the end of the build
 # > Configure project :appsearch:appsearch\-local\-backend
 Configuration on demand is an incubating feature\.
+Calculating task graph as configuration cache cannot be reused because the set of Gradle properties has changed\.
 # > Task :listTaskOutputs
 Deprecated Gradle features were used in this build, making it incompatible with Gradle [0-9]+\.[0-9]+\.
 BUILD SUCCESSFUL in .*
diff --git a/gradlew b/gradlew
index 66189ab..e8d45ff 100755
--- a/gradlew
+++ b/gradlew
@@ -27,17 +27,9 @@
     mkdir -p "$DIST_DIR"
     DIST_DIR="$(cd $DIST_DIR && pwd -P)"
 
-    #Set the initial heap size to match the max heap size,
-    #by replacing a string like "-Xmx1g" with one like "-Xms1g -Xmx1g"
-    MAX_MEM=32g
-    ORG_GRADLE_JVMARGS="$(echo $ORG_GRADLE_JVMARGS | sed "s/-Xmx\([^ ]*\)/-Xms$MAX_MEM -Xmx$MAX_MEM/")"
-
     # tell Gradle where to put a heap dump on failure
     ORG_GRADLE_JVMARGS="$(echo $ORG_GRADLE_JVMARGS | sed "s|$| -XX:HeapDumpPath=$DIST_DIR|")"
 
-    # Increase the compiler cache size: b/260643754 . Remove when updating to JDK 20 ( https://bugs.openjdk.org/browse/JDK-8295724 )
-    ORG_GRADLE_JVMARGS="$(echo $ORG_GRADLE_JVMARGS | sed "s|$| -XX:ReservedCodeCacheSize=576M|")"
-
     # We don't set a default DIST_DIR in an else clause here because Studio doesn't use gradlew
     # and doesn't set DIST_DIR and we want gradlew and Studio to match
 fi
@@ -272,7 +264,8 @@
        --stacktrace\
        -Pandroidx.summarizeStderr\
        -Pandroidx.enableAffectedModuleDetection\
-       --no-watch-fs"
+       --no-watch-fs\
+       -Pandroidx.highMemory"
     fi
   fi
   if [ "$compact" == "--strict" ]; then
@@ -316,6 +309,16 @@
   fi
 done
 
+if [[ " ${@} " =~ " -Pandroidx.highMemory " ]]; then
+    #Set the initial heap size to match the max heap size,
+    #by replacing a string like "-Xmx1g" with one like "-Xms1g -Xmx1g"
+    MAX_MEM=32g
+    ORG_GRADLE_JVMARGS="$(echo $ORG_GRADLE_JVMARGS | sed "s/-Xmx\([^ ]*\)/-Xms$MAX_MEM -Xmx$MAX_MEM/")"
+
+    # Increase the compiler cache size: b/260643754 . Remove when updating to JDK 20 ( https://bugs.openjdk.org/browse/JDK-8295724 )
+    ORG_GRADLE_JVMARGS="$(echo $ORG_GRADLE_JVMARGS | sed "s|$| -XX:ReservedCodeCacheSize=576M|")"
+fi
+
 # check whether the user has requested profiling via yourkit
 yourkitArgPrefix="androidx.profile.yourkitAgentPath"
 yourkitAgentPath=""
diff --git a/javascriptengine/javascriptengine/api/current.txt b/javascriptengine/javascriptengine/api/current.txt
index 96064bd..f8a7b67 100644
--- a/javascriptengine/javascriptengine/api/current.txt
+++ b/javascriptengine/javascriptengine/api/current.txt
@@ -22,6 +22,7 @@
 
   public class IsolateTerminatedException extends androidx.javascriptengine.JavaScriptException {
     ctor public IsolateTerminatedException();
+    ctor public IsolateTerminatedException(String);
   }
 
   public interface JavaScriptConsoleCallback {
@@ -49,18 +50,21 @@
     ctor public JavaScriptException(String);
   }
 
-  public final class JavaScriptIsolate implements java.lang.AutoCloseable {
+  @javax.annotation.concurrent.ThreadSafe public final class JavaScriptIsolate implements java.lang.AutoCloseable {
+    method public void addOnTerminatedCallback(androidx.core.util.Consumer<androidx.javascriptengine.TerminationInfo!>);
+    method public void addOnTerminatedCallback(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.javascriptengine.TerminationInfo!>);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public void clearConsoleCallback();
     method public void close();
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_EVALUATE_FROM_FD, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public com.google.common.util.concurrent.ListenableFuture<java.lang.String!> evaluateJavaScriptAsync(android.content.res.AssetFileDescriptor);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_EVALUATE_FROM_FD, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public com.google.common.util.concurrent.ListenableFuture<java.lang.String!> evaluateJavaScriptAsync(android.os.ParcelFileDescriptor);
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.String!> evaluateJavaScriptAsync(String);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_PROVIDE_CONSUME_ARRAY_BUFFER, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public void provideNamedData(String, byte[]);
+    method public void removeOnTerminatedCallback(androidx.core.util.Consumer<androidx.javascriptengine.TerminationInfo!>);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public void setConsoleCallback(androidx.javascriptengine.JavaScriptConsoleCallback);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public void setConsoleCallback(java.util.concurrent.Executor, androidx.javascriptengine.JavaScriptConsoleCallback);
   }
 
-  public final class JavaScriptSandbox implements java.lang.AutoCloseable {
+  @javax.annotation.concurrent.ThreadSafe public final class JavaScriptSandbox implements java.lang.AutoCloseable {
     method public void close();
     method public static com.google.common.util.concurrent.ListenableFuture<androidx.javascriptengine.JavaScriptSandbox!> createConnectedInstanceAsync(android.content.Context);
     method public androidx.javascriptengine.JavaScriptIsolate createIsolate();
@@ -84,11 +88,21 @@
 
   public final class SandboxDeadException extends androidx.javascriptengine.IsolateTerminatedException {
     ctor public SandboxDeadException();
+    ctor public SandboxDeadException(String);
   }
 
   public final class SandboxUnsupportedException extends java.lang.RuntimeException {
     ctor public SandboxUnsupportedException(String);
   }
 
+  public final class TerminationInfo {
+    method public String getMessage();
+    method public int getStatus();
+    method public String getStatusString();
+    field public static final int STATUS_MEMORY_LIMIT_EXCEEDED = 3; // 0x3
+    field public static final int STATUS_SANDBOX_DEAD = 2; // 0x2
+    field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
+  }
+
 }
 
diff --git a/javascriptengine/javascriptengine/api/restricted_current.txt b/javascriptengine/javascriptengine/api/restricted_current.txt
index 96064bd..f8a7b67 100644
--- a/javascriptengine/javascriptengine/api/restricted_current.txt
+++ b/javascriptengine/javascriptengine/api/restricted_current.txt
@@ -22,6 +22,7 @@
 
   public class IsolateTerminatedException extends androidx.javascriptengine.JavaScriptException {
     ctor public IsolateTerminatedException();
+    ctor public IsolateTerminatedException(String);
   }
 
   public interface JavaScriptConsoleCallback {
@@ -49,18 +50,21 @@
     ctor public JavaScriptException(String);
   }
 
-  public final class JavaScriptIsolate implements java.lang.AutoCloseable {
+  @javax.annotation.concurrent.ThreadSafe public final class JavaScriptIsolate implements java.lang.AutoCloseable {
+    method public void addOnTerminatedCallback(androidx.core.util.Consumer<androidx.javascriptengine.TerminationInfo!>);
+    method public void addOnTerminatedCallback(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.javascriptengine.TerminationInfo!>);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public void clearConsoleCallback();
     method public void close();
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_EVALUATE_FROM_FD, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public com.google.common.util.concurrent.ListenableFuture<java.lang.String!> evaluateJavaScriptAsync(android.content.res.AssetFileDescriptor);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_EVALUATE_FROM_FD, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public com.google.common.util.concurrent.ListenableFuture<java.lang.String!> evaluateJavaScriptAsync(android.os.ParcelFileDescriptor);
     method public com.google.common.util.concurrent.ListenableFuture<java.lang.String!> evaluateJavaScriptAsync(String);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_PROVIDE_CONSUME_ARRAY_BUFFER, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public void provideNamedData(String, byte[]);
+    method public void removeOnTerminatedCallback(androidx.core.util.Consumer<androidx.javascriptengine.TerminationInfo!>);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public void setConsoleCallback(androidx.javascriptengine.JavaScriptConsoleCallback);
     method @RequiresFeature(name=androidx.javascriptengine.JavaScriptSandbox.JS_FEATURE_CONSOLE_MESSAGING, enforcement="androidx.javascriptengine.JavaScriptSandbox#isFeatureSupported") public void setConsoleCallback(java.util.concurrent.Executor, androidx.javascriptengine.JavaScriptConsoleCallback);
   }
 
-  public final class JavaScriptSandbox implements java.lang.AutoCloseable {
+  @javax.annotation.concurrent.ThreadSafe public final class JavaScriptSandbox implements java.lang.AutoCloseable {
     method public void close();
     method public static com.google.common.util.concurrent.ListenableFuture<androidx.javascriptengine.JavaScriptSandbox!> createConnectedInstanceAsync(android.content.Context);
     method public androidx.javascriptengine.JavaScriptIsolate createIsolate();
@@ -84,11 +88,21 @@
 
   public final class SandboxDeadException extends androidx.javascriptengine.IsolateTerminatedException {
     ctor public SandboxDeadException();
+    ctor public SandboxDeadException(String);
   }
 
   public final class SandboxUnsupportedException extends java.lang.RuntimeException {
     ctor public SandboxUnsupportedException(String);
   }
 
+  public final class TerminationInfo {
+    method public String getMessage();
+    method public int getStatus();
+    method public String getStatusString();
+    field public static final int STATUS_MEMORY_LIMIT_EXCEEDED = 3; // 0x3
+    field public static final int STATUS_SANDBOX_DEAD = 2; // 0x2
+    field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
+  }
+
 }
 
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateTerminatedException.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateTerminatedException.java
index 8548c19..84ea3ab 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateTerminatedException.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/IsolateTerminatedException.java
@@ -17,7 +17,6 @@
 package androidx.javascriptengine;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
 import androidx.core.util.Consumer;
 
 import java.util.concurrent.Executor;
@@ -50,7 +49,7 @@
     public IsolateTerminatedException() {
         super();
     }
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
+
     public IsolateTerminatedException(@NonNull String message) {
         super(message);
     }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptIsolate.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptIsolate.java
index dde4b27..eea5139 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptIsolate.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptIsolate.java
@@ -16,6 +16,7 @@
 
 package androidx.javascriptengine;
 
+import android.annotation.SuppressLint;
 import android.content.res.AssetFileDescriptor;
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
@@ -25,7 +26,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresFeature;
-import androidx.annotation.RestrictTo;
 import androidx.core.util.Consumer;
 
 import com.google.common.util.concurrent.ListenableFuture;
@@ -37,6 +37,7 @@
 import java.util.concurrent.Executor;
 
 import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.ThreadSafe;
 
 /**
  * Environment within a {@link JavaScriptSandbox} where JavaScript is executed.
@@ -54,6 +55,7 @@
  * <p>
  * This class is thread-safe.
  */
+@ThreadSafe
 public final class JavaScriptIsolate implements AutoCloseable {
     private static final String TAG = "JavaScriptIsolate";
     private final Object mLock = new Object();
@@ -475,7 +477,7 @@
      * @param callback Consumer to be called with TerminationInfo when a crash occurs.
      * @throws IllegalStateException if the callback is already registered (using any executor).
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @SuppressLint("RegistrationName")
     public void addOnTerminatedCallback(@NonNull Executor executor,
             @NonNull Consumer<TerminationInfo> callback) {
         Objects.requireNonNull(executor);
@@ -494,7 +496,7 @@
      * @param callback Consumer to be called with TerminationInfo when a crash occurs.
      * @throws IllegalStateException if the callback is already registered (using any executor).
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @SuppressLint("RegistrationName")
     public void addOnTerminatedCallback(@NonNull Consumer<TerminationInfo> callback) {
         addOnTerminatedCallback(mJsSandbox.getMainExecutor(), callback);
     }
@@ -504,7 +506,7 @@
      *
      * @param callback The callback to unregister, if currently registered.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @SuppressLint("RegistrationName")
     public void removeOnTerminatedCallback(@NonNull Consumer<TerminationInfo> callback) {
         Objects.requireNonNull(callback);
         synchronized (mLock) {
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptSandbox.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptSandbox.java
index b3f65eb..b35dbd2 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptSandbox.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/JavaScriptSandbox.java
@@ -61,6 +61,7 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.ThreadSafe;
 
 /**
  * Sandbox that provides APIs for JavaScript evaluation in a restricted environment.
@@ -83,6 +84,7 @@
  * can create their own {@link JavaScriptIsolate} objects from it but the
  * {@link JavaScriptIsolate} object cannot be shared.
  */
+@ThreadSafe
 public final class JavaScriptSandbox implements AutoCloseable {
     private static final String TAG = "JavaScriptSandbox";
     // TODO(crbug.com/1297672): Add capability to this class to support spawning
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/SandboxDeadException.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/SandboxDeadException.java
index f3439b7..5cc86a3 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/SandboxDeadException.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/SandboxDeadException.java
@@ -17,7 +17,6 @@
 package androidx.javascriptengine;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
 
 /**
  * Exception thrown when evaluation is terminated due the {@link JavaScriptSandbox} being dead.
@@ -28,7 +27,7 @@
     public SandboxDeadException() {
         super();
     }
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
+
     public SandboxDeadException(@NonNull String message) {
         super(message);
     }
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/TerminationInfo.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/TerminationInfo.java
index fc828de..db18013 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/TerminationInfo.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/TerminationInfo.java
@@ -28,8 +28,7 @@
 /**
  * Information about how and why an isolate has terminated.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-public class TerminationInfo {
+public final class TerminationInfo {
     /**
      * Termination status code for an isolate.
      */
diff --git a/libraryversions.toml b/libraryversions.toml
index 89da799..09d7dc2 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -102,7 +102,7 @@
 PRINT = "1.1.0-beta01"
 PRIVACYSANDBOX_ADS = "1.1.0-beta02"
 PRIVACYSANDBOX_PLUGINS = "1.0.0-alpha03"
-PRIVACYSANDBOX_SDKRUNTIME = "1.0.0-alpha09"
+PRIVACYSANDBOX_SDKRUNTIME = "1.0.0-alpha10"
 PRIVACYSANDBOX_TOOLS = "1.0.0-alpha06"
 PRIVACYSANDBOX_UI = "1.0.0-alpha06"
 PROFILEINSTALLER = "1.4.0-alpha01"
@@ -163,7 +163,7 @@
 WINDOW_EXTENSIONS_CORE = "1.1.0-alpha01"
 WINDOW_SIDECAR = "1.0.0-rc01"
 # Do not remove comment
-WORK = "2.9.0-rc01"
+WORK = "2.10.0-alpha01"
 
 [groups]
 ACTIVITY = { group = "androidx.activity", atomicGroupVersion = "versions.ACTIVITY" }
diff --git a/media/version-compat-tests/build.gradle b/media/version-compat-tests/build.gradle
new file mode 100644
index 0000000..92fc391
--- /dev/null
+++ b/media/version-compat-tests/build.gradle
@@ -0,0 +1,5 @@
+// This project creates some version compat test artifacts
+// See TestSuiteConfiguration.kt
+plugins {
+    id("AndroidXPlugin")
+}
diff --git a/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java b/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
index 9768f00..1065a82 100644
--- a/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
+++ b/media/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
@@ -112,6 +112,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -329,6 +330,7 @@
 
     @Test
     @SmallTest
+    @Ignore("flaky: b/297535302")
     public void testGetPlaybackStateWithPositionUpdate() throws InterruptedException {
         final long stateSetTime = SystemClock.elapsedRealtime();
         PlaybackStateCompat stateIn = new PlaybackStateCompat.Builder()
diff --git a/media/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java b/media/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
index 9b180e8..615ca1b 100644
--- a/media/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
+++ b/media/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
@@ -112,6 +112,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -329,6 +330,7 @@
 
     @Test
     @SmallTest
+    @Ignore("flaky: b/297535302")
     public void testGetPlaybackStateWithPositionUpdate() throws InterruptedException {
         final long stateSetTime = SystemClock.elapsedRealtime();
         PlaybackStateCompat stateIn = new PlaybackStateCompat.Builder()
diff --git a/media2/media2-session/version-compat-tests/build.gradle b/media2/media2-session/version-compat-tests/build.gradle
new file mode 100644
index 0000000..92fc391
--- /dev/null
+++ b/media2/media2-session/version-compat-tests/build.gradle
@@ -0,0 +1,5 @@
+// This project creates some version compat test artifacts
+// See TestSuiteConfiguration.kt
+plugins {
+    id("AndroidXPlugin")
+}
diff --git a/test/screenshot/screenshot-proto/build.gradle b/test/screenshot/screenshot-proto/build.gradle
index 6940586..879e232 100644
--- a/test/screenshot/screenshot-proto/build.gradle
+++ b/test/screenshot/screenshot-proto/build.gradle
@@ -19,6 +19,7 @@
 plugins {
     id("java-library")
     id("com.google.protobuf")
+    id("AndroidXPlugin")
 }
 
 dependencies {
@@ -44,3 +45,12 @@
         }
     }
 }
+
+afterEvaluate {
+    lint {
+        lintOptions {
+            // protobuf generates unannotated methods
+            disable("UnknownNullness")
+        }
+    }
+}
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 c05d7b5..42cefbb 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
@@ -181,7 +181,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = HeadAndTailAnimationDuration + HeadAndTailDelayDuration
-                0f at 0 with CircularEasing
+                0f at 0 using CircularEasing
                 JumpRotationAngle at HeadAndTailAnimationDuration
             }
         )
@@ -193,7 +193,7 @@
         infiniteRepeatable(
             animation = keyframes {
                 durationMillis = HeadAndTailAnimationDuration + HeadAndTailDelayDuration
-                0f at HeadAndTailDelayDuration with CircularEasing
+                0f at HeadAndTailDelayDuration using CircularEasing
                 JumpRotationAngle at durationMillis
             }
         )
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
index 1a1b0e7..7396864 100644
--- 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
@@ -59,7 +59,15 @@
 import kotlin.math.abs
 
 /**
- * [SwipeToReveal] Material composable for Chips. This provides the default style for consistency.
+ * [SwipeToReveal] Material composable for [Chip]s. This adds the option to configure up to two
+ * additional actions on the [Chip]: a mandatory [primaryAction] and an optional
+ * [secondaryAction]. These actions are initially hidden and revealed only when the [content] is
+ * swiped. These additional actions can be triggered by clicking on them after they are revealed.
+ * [primaryAction] can also be triggered by performing a full swipe of the [content].
+ *
+ * For actions like "Delete", consider adding [undoPrimaryAction] (displayed when the
+ * [primaryAction] is activated) and/or [undoSecondaryAction] (displayed when the [secondaryAction]
+ * is activated). Adding undo composables allow users to undo the action that they just performed.
  *
  * Example of [SwipeToRevealChip] with primary and secondary actions
  * @sample androidx.wear.compose.material.samples.SwipeToRevealChipSample
@@ -112,7 +120,15 @@
 }
 
 /**
- * [SwipeToReveal] Material composable for Cards. This provides the default style for consistency.
+ * [SwipeToReveal] Material composable for [Card]s. This adds the option to configure up to two
+ * additional actions on the [Card]: a mandatory [primaryAction] and an optional
+ * [secondaryAction]. These actions are initially hidden and revealed only when the [content] is
+ * swiped. These additional actions can be triggered by clicking on them after they are revealed.
+ * [primaryAction] can also be triggered by performing a full swipe of the [content].
+ *
+ * For actions like "Delete", consider adding [undoPrimaryAction] (displayed when the
+ * [primaryAction] is activated) and/or [undoSecondaryAction] (displayed when the [secondaryAction]
+ * is activated). Adding undo composables allow users to undo the action that they just performed.
  *
  * Example of [SwipeToRevealCard] with primary and secondary actions
  * @sample androidx.wear.compose.material.samples.SwipeToRevealCardSample
@@ -176,17 +192,19 @@
     public val CardActionShape = RoundedCornerShape(40.dp)
 
     /**
-     * Colors to be used with different actions in [SwipeToReveal].
+     * The recommended colors used to display the contents of the
+     * primary, secondary and undo actions in [SwipeToReveal].
      *
-     * @param primaryActionBackgroundColor The background color (color of the shape) of the primary
-     * action
-     * @param primaryActionContentColor The content color (text and icon) of the primary action
+     * @param primaryActionBackgroundColor The background color (color of the shape) of the
+     * [primaryAction]
+     * @param primaryActionContentColor The content color (text and icon) of the [primaryAction]
      * @param secondaryActionBackgroundColor The background color (color of the shape) of the
-     * secondary action
-     * @param secondaryActionContentColor The content color (text and icon) of the secondary
-     * action
-     * @param undoActionBackgroundColor The background color (color of the shape) of the undo action
-     * @param undoActionContentColor The content color (text) of the undo action
+     * [secondaryAction]
+     * @param secondaryActionContentColor The content color (text and icon) of the
+     * [secondaryAction]
+     * @param undoActionBackgroundColor The background color (color of the shape) of the
+     * [undoAction]
+     * @param undoActionContentColor The content color (text) of the [undoAction]
      */
     @Composable
     public fun actionColors(
@@ -316,6 +334,7 @@
 
 /**
  * A class representing the colors applied in [SwipeToReveal] actions.
+ * See [SwipeToRevealDefaults.actionColors].
  *
  * @param primaryActionBackgroundColor Color of the shape (background) of primary action
  * @param primaryActionContentColor Color of icon or text used in the primary action
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/dialog/Dialog.android.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/dialog/Dialog.android.kt
index 966ee28..253f341 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/dialog/Dialog.android.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/dialog/Dialog.android.kt
@@ -262,7 +262,7 @@
                 // Outro
                 durationMillis = QUICK + RAPID
                 1f at 0
-                0.9f at RAPID with STANDARD_IN
+                0.9f at RAPID using STANDARD_IN
                 0.0f at RAPID + QUICK
             }
         }
@@ -285,7 +285,7 @@
                 // Intro
                 durationMillis = QUICK + RAPID
                 0.0f at 0
-                0.1f at RAPID with STANDARD_IN
+                0.1f at RAPID using STANDARD_IN
                 1f at RAPID + QUICK
             }
 
diff --git a/webkit/webkit/api/current.txt b/webkit/webkit/api/current.txt
index ebb7e57..aa2bfe1 100644
--- a/webkit/webkit/api/current.txt
+++ b/webkit/webkit/api/current.txt
@@ -27,6 +27,23 @@
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDirectoryBasePaths(android.content.Context, java.io.File, java.io.File);
   }
 
+  public interface Profile {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.CookieManager getCookieManager();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.GeolocationPermissions getGeolocationPermissions();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public String getName();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.ServiceWorkerController getServiceWorkerController();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.WebStorage getWebStorage();
+    field public static final String DEFAULT_PROFILE_NAME = "Default";
+  }
+
+  public interface ProfileStore {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public boolean deleteProfile(String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public java.util.List<java.lang.String!> getAllProfileNames();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProfileStore getInstance();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile getOrCreateProfile(String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile? getProfile(String);
+  }
+
   public final class ProxyConfig {
     method public java.util.List<java.lang.String!> getBypassRules();
     method public java.util.List<androidx.webkit.ProxyConfig.ProxyRule!> getProxyRules();
@@ -197,6 +214,7 @@
   }
 
   public class WebSettingsCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getAttributionRegistrationBehavior(android.webkit.WebSettings);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings);
     method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDark(android.webkit.WebSettings);
@@ -207,6 +225,7 @@
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.UserAgentMetadata getUserAgentMetadata(android.webkit.WebSettings);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isAlgorithmicDarkeningAllowed(android.webkit.WebSettings);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAlgorithmicDarkeningAllowed(android.webkit.WebSettings, boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAttributionRegistrationBehavior(android.webkit.WebSettings, int);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings, boolean);
     method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDark(android.webkit.WebSettings, int);
@@ -215,6 +234,10 @@
     method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setRequestedWithHeaderOriginAllowList(android.webkit.WebSettings, java.util.Set<java.lang.String!>);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setUserAgentMetadata(android.webkit.WebSettings, androidx.webkit.UserAgentMetadata);
+    field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER = 3; // 0x3
+    field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER = 1; // 0x1
+    field public static final int ATTRIBUTION_BEHAVIOR_DISABLED = 0; // 0x0
+    field public static final int ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER = 2; // 0x2
     field @Deprecated public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING = 2; // 0x2
     field @Deprecated public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY = 0; // 0x0
     field @Deprecated public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY = 1; // 0x1
@@ -268,6 +291,7 @@
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void addWebMessageListener(android.webkit.WebView, String, java.util.Set<java.lang.String!>, androidx.webkit.WebViewCompat.WebMessageListener);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
     method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.Profile getProfile(android.webkit.WebView);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_VARIATIONS_HEADER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static String getVariationsHeader();
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_CHROME_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
@@ -278,6 +302,7 @@
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.VISUAL_STATE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.POST_WEB_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setProfile(android.webkit.WebView, String);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ALLOWLIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingAllowlist(java.util.Set<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
     method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_WHITELIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
@@ -297,6 +322,7 @@
     method public static boolean isFeatureSupported(String);
     method public static boolean isStartupFeatureSupported(android.content.Context, String);
     field public static final String ALGORITHMIC_DARKENING = "ALGORITHMIC_DARKENING";
+    field public static final String ATTRIBUTION_REGISTRATION_BEHAVIOR = "ATTRIBUTION_REGISTRATION_BEHAVIOR";
     field public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
     field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
     field public static final String DOCUMENT_START_SCRIPT = "DOCUMENT_START_SCRIPT";
@@ -309,6 +335,7 @@
     field public static final String GET_WEB_VIEW_CLIENT = "GET_WEB_VIEW_CLIENT";
     field public static final String GET_WEB_VIEW_RENDERER = "GET_WEB_VIEW_RENDERER";
     field public static final String MULTI_PROCESS = "MULTI_PROCESS";
+    field public static final String MULTI_PROFILE = "MULTI_PROFILE";
     field public static final String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
     field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
     field public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
diff --git a/webkit/webkit/api/restricted_current.txt b/webkit/webkit/api/restricted_current.txt
index ebb7e57..aa2bfe1 100644
--- a/webkit/webkit/api/restricted_current.txt
+++ b/webkit/webkit/api/restricted_current.txt
@@ -27,6 +27,23 @@
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.STARTUP_FEATURE_SET_DIRECTORY_BASE_PATHS, enforcement="androidx.webkit.WebViewFeature#isConfigFeatureSupported(String, Context)") public androidx.webkit.ProcessGlobalConfig setDirectoryBasePaths(android.content.Context, java.io.File, java.io.File);
   }
 
+  public interface Profile {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.CookieManager getCookieManager();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.GeolocationPermissions getGeolocationPermissions();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public String getName();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.ServiceWorkerController getServiceWorkerController();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public android.webkit.WebStorage getWebStorage();
+    field public static final String DEFAULT_PROFILE_NAME = "Default";
+  }
+
+  public interface ProfileStore {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public boolean deleteProfile(String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public java.util.List<java.lang.String!> getAllProfileNames();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.ProfileStore getInstance();
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile getOrCreateProfile(String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public androidx.webkit.Profile? getProfile(String);
+  }
+
   public final class ProxyConfig {
     method public java.util.List<java.lang.String!> getBypassRules();
     method public java.util.List<androidx.webkit.ProxyConfig.ProxyRule!> getProxyRules();
@@ -197,6 +214,7 @@
   }
 
   public class WebSettingsCompat {
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getAttributionRegistrationBehavior(android.webkit.WebSettings);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean getEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings);
     method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static int getForceDark(android.webkit.WebSettings);
@@ -207,6 +225,7 @@
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.UserAgentMetadata getUserAgentMetadata(android.webkit.WebSettings);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static boolean isAlgorithmicDarkeningAllowed(android.webkit.WebSettings);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.ALGORITHMIC_DARKENING, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAlgorithmicDarkeningAllowed(android.webkit.WebSettings, boolean);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setAttributionRegistrationBehavior(android.webkit.WebSettings, int);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.DISABLED_ACTION_MODE_MENU_ITEMS, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.ENTERPRISE_AUTHENTICATION_APP_LINK_POLICY, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setEnterpriseAuthenticationAppLinkPolicyEnabled(android.webkit.WebSettings, boolean);
     method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.FORCE_DARK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setForceDark(android.webkit.WebSettings, int);
@@ -215,6 +234,10 @@
     method @RequiresFeature(name="REQUESTED_WITH_HEADER_ALLOW_LIST", enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setRequestedWithHeaderOriginAllowList(android.webkit.WebSettings, java.util.Set<java.lang.String!>);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ENABLE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.USER_AGENT_METADATA, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setUserAgentMetadata(android.webkit.WebSettings, androidx.webkit.UserAgentMetadata);
+    field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER = 3; // 0x3
+    field public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER = 1; // 0x1
+    field public static final int ATTRIBUTION_BEHAVIOR_DISABLED = 0; // 0x0
+    field public static final int ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER = 2; // 0x2
     field @Deprecated public static final int DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING = 2; // 0x2
     field @Deprecated public static final int DARK_STRATEGY_USER_AGENT_DARKENING_ONLY = 0; // 0x0
     field @Deprecated public static final int DARK_STRATEGY_WEB_THEME_DARKENING_ONLY = 1; // 0x1
@@ -268,6 +291,7 @@
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void addWebMessageListener(android.webkit.WebView, String, java.util.Set<java.lang.String!>, androidx.webkit.WebViewCompat.WebMessageListener);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.CREATE_WEB_MESSAGE_CHANNEL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.WebMessagePortCompat![] createWebMessageChannel(android.webkit.WebView);
     method public static android.content.pm.PackageInfo? getCurrentWebViewPackage(android.content.Context);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static androidx.webkit.Profile getProfile(android.webkit.WebView);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_PRIVACY_POLICY_URL, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_VARIATIONS_HEADER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static String getVariationsHeader();
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.GET_WEB_CHROME_CLIENT, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static android.webkit.WebChromeClient? getWebChromeClient(android.webkit.WebView);
@@ -278,6 +302,7 @@
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.VISUAL_STATE_CALLBACK, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.POST_WEB_MESSAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void postWebMessage(android.webkit.WebView, androidx.webkit.WebMessageCompat, android.net.Uri);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_MESSAGE_LISTENER, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void removeWebMessageListener(android.webkit.WebView, String);
+    method @RequiresFeature(name=androidx.webkit.WebViewFeature.MULTI_PROFILE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setProfile(android.webkit.WebView, String);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_ALLOWLIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingAllowlist(java.util.Set<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
     method @Deprecated @RequiresFeature(name=androidx.webkit.WebViewFeature.SAFE_BROWSING_WHITELIST, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String!>, android.webkit.ValueCallback<java.lang.Boolean!>?);
     method @RequiresFeature(name=androidx.webkit.WebViewFeature.WEB_VIEW_RENDERER_CLIENT_BASIC_USAGE, enforcement="androidx.webkit.WebViewFeature#isFeatureSupported") public static void setWebViewRenderProcessClient(android.webkit.WebView, androidx.webkit.WebViewRenderProcessClient?);
@@ -297,6 +322,7 @@
     method public static boolean isFeatureSupported(String);
     method public static boolean isStartupFeatureSupported(android.content.Context, String);
     field public static final String ALGORITHMIC_DARKENING = "ALGORITHMIC_DARKENING";
+    field public static final String ATTRIBUTION_REGISTRATION_BEHAVIOR = "ATTRIBUTION_REGISTRATION_BEHAVIOR";
     field public static final String CREATE_WEB_MESSAGE_CHANNEL = "CREATE_WEB_MESSAGE_CHANNEL";
     field public static final String DISABLED_ACTION_MODE_MENU_ITEMS = "DISABLED_ACTION_MODE_MENU_ITEMS";
     field public static final String DOCUMENT_START_SCRIPT = "DOCUMENT_START_SCRIPT";
@@ -309,6 +335,7 @@
     field public static final String GET_WEB_VIEW_CLIENT = "GET_WEB_VIEW_CLIENT";
     field public static final String GET_WEB_VIEW_RENDERER = "GET_WEB_VIEW_RENDERER";
     field public static final String MULTI_PROCESS = "MULTI_PROCESS";
+    field public static final String MULTI_PROFILE = "MULTI_PROFILE";
     field public static final String OFF_SCREEN_PRERASTER = "OFF_SCREEN_PRERASTER";
     field public static final String POST_WEB_MESSAGE = "POST_WEB_MESSAGE";
     field public static final String PROXY_OVERRIDE = "PROXY_OVERRIDE";
diff --git a/webkit/webkit/src/main/java/androidx/webkit/Profile.java b/webkit/webkit/src/main/java/androidx/webkit/Profile.java
index ccf3da4..14d9e0f 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/Profile.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/Profile.java
@@ -23,17 +23,13 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresFeature;
-import androidx.annotation.RestrictTo;
 
 /**
  * A Profile represents one browsing session for WebView.
  * <p> You can have multiple profiles and each profile holds its own set of data. The creation
  * and deletion of the Profile is being managed by {@link ProfileStore}.
  *
- * @hide
- *
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public interface Profile {
 
     /**
@@ -61,7 +57,7 @@
     @NonNull
     @RequiresFeature(name = WebViewFeature.MULTI_PROFILE,
             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
-    CookieManager getCookieManager() throws IllegalStateException;
+    CookieManager getCookieManager();
 
     /**
      * Returns the profile's web storage.
@@ -74,7 +70,7 @@
     @NonNull
     @RequiresFeature(name = WebViewFeature.MULTI_PROFILE,
             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
-    WebStorage getWebStorage() throws IllegalStateException;
+    WebStorage getWebStorage();
 
     /**
      * Returns the geolocation permissions of the profile.
@@ -87,7 +83,7 @@
     @NonNull
     @RequiresFeature(name = WebViewFeature.MULTI_PROFILE,
             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
-    GeolocationPermissions getGeolocationPermissions() throws IllegalStateException;
+    GeolocationPermissions getGeolocationPermissions();
 
     /**
      * Returns the service worker controller of the profile.
@@ -100,6 +96,6 @@
     @NonNull
     @RequiresFeature(name = WebViewFeature.MULTI_PROFILE,
             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
-    ServiceWorkerController getServiceWorkerController() throws IllegalStateException;
+    ServiceWorkerController getServiceWorkerController();
 
 }
diff --git a/webkit/webkit/src/main/java/androidx/webkit/ProfileStore.java b/webkit/webkit/src/main/java/androidx/webkit/ProfileStore.java
index f7a2af9..4ebb193 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/ProfileStore.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/ProfileStore.java
@@ -19,7 +19,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresFeature;
-import androidx.annotation.RestrictTo;
 import androidx.webkit.internal.ApiFeature;
 import androidx.webkit.internal.ProfileStoreImpl;
 import androidx.webkit.internal.WebViewFeatureInternal;
@@ -41,10 +40,7 @@
  *    profileStore.deleteProfile("profile_test");
  *
  * </pre>
- *
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public interface ProfileStore {
 
     /**
@@ -128,6 +124,5 @@
      */
     @RequiresFeature(name = WebViewFeature.MULTI_PROFILE,
             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
-    boolean deleteProfile(@NonNull String name) throws IllegalStateException,
-            IllegalArgumentException;
+    boolean deleteProfile(@NonNull String name);
 }
diff --git a/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java b/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
index 4a544da..08ed011 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
@@ -783,7 +783,6 @@
      * happen depending on the installed version of WebView, but any response is discarded and
      * nothing will be stored on the device.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public static final int ATTRIBUTION_BEHAVIOR_DISABLED =
             WebSettingsBoundaryInterface.AttributionBehavior.DISABLED;
     /**
@@ -793,7 +792,6 @@
      * <p>
      * This is the default behavior.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_WEB_TRIGGER =
             WebSettingsBoundaryInterface.AttributionBehavior.APP_SOURCE_AND_WEB_TRIGGER;
     /**
@@ -804,14 +802,12 @@
      * <a href="https://developer.android.com/design-for-safety/privacy-sandbox/attribution-app-to-web#register-attribution">
      *     use web sources</a>.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public static final int ATTRIBUTION_BEHAVIOR_WEB_SOURCE_AND_WEB_TRIGGER =
             WebSettingsBoundaryInterface.AttributionBehavior.WEB_SOURCE_AND_WEB_TRIGGER;
     /**
      * AttributionRegistrationBehavior that allows apps to register app sources and app triggers
      * from WebView.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public static final int ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER =
             WebSettingsBoundaryInterface.AttributionBehavior.APP_SOURCE_AND_APP_TRIGGER;
 
@@ -842,7 +838,6 @@
      * @param settings Settings retrieved from {@link WebView#getSettings()}.
      * @param behavior New behavior to use.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @RequiresFeature(name = WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR,
             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
     public static void setAttributionRegistrationBehavior(@NonNull WebSettings settings,
@@ -866,7 +861,6 @@
      * @see #ATTRIBUTION_BEHAVIOR_APP_SOURCE_AND_APP_TRIGGER
      * @param settings Settings retrieved from {@link WebView#getSettings()}.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @RequiresFeature(name = WebViewFeature.ATTRIBUTION_REGISTRATION_BEHAVIOR,
             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
     @AttributionRegistrationBehavior
diff --git a/webkit/webkit/src/main/java/androidx/webkit/WebViewCompat.java b/webkit/webkit/src/main/java/androidx/webkit/WebViewCompat.java
index 8deb404..6432c54 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/WebViewCompat.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/WebViewCompat.java
@@ -1092,12 +1092,11 @@
      * called on the WebView before this method.
      * @throws IllegalStateException if the WebView has previously navigated to a web page.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @RequiresFeature(
             name = WebViewFeature.MULTI_PROFILE,
             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
     public static void setProfile(@NonNull WebView webView,
-            @NonNull String profileName) throws IllegalStateException {
+            @NonNull String profileName) {
         final ApiFeature.NoFramework feature = WebViewFeatureInternal.MULTI_PROFILE;
         if (feature.isSupportedByWebView()) {
             getProvider(webView).setProfileWithName(profileName);
@@ -1119,11 +1118,10 @@
      * @throws IllegalStateException if the WebView has been destroyed.
      */
     @NonNull
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @RequiresFeature(
             name = WebViewFeature.MULTI_PROFILE,
             enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
-    public static Profile getProfile(@NonNull WebView webView) throws IllegalStateException {
+    public static Profile getProfile(@NonNull WebView webView) {
         final ApiFeature.NoFramework feature = WebViewFeatureInternal.MULTI_PROFILE;
         if (feature.isSupportedByWebView()) {
             return getProvider(webView).getProfile();
diff --git a/webkit/webkit/src/main/java/androidx/webkit/WebViewFeature.java b/webkit/webkit/src/main/java/androidx/webkit/WebViewFeature.java
index 11936ee..fa09c22 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/WebViewFeature.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/WebViewFeature.java
@@ -557,7 +557,6 @@
      * {@link ProfileStore#deleteProfile(String)}.
      * {@link ProfileStore#getInstance()}.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public static final String MULTI_PROFILE = "MULTI_PROFILE";
 
     /**
@@ -566,7 +565,6 @@
      * {@link androidx.webkit.WebSettingsCompat#setAttributionRegistrationBehavior(WebSettings, int)}
      * {@link androidx.webkit.WebSettingsCompat#getAttributionRegistrationBehavior(WebSettings)}
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public static final String ATTRIBUTION_REGISTRATION_BEHAVIOR =
             "ATTRIBUTION_REGISTRATION_BEHAVIOR";
 
diff --git a/webkit/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java b/webkit/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java
index 4922c47..4790c17 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java
@@ -557,7 +557,6 @@
      * {@link ProfileStore#deleteProfile(String)}.
      * {@link ProfileStore#getInstance()}.
      */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public static final ApiFeature.NoFramework MULTI_PROFILE =
             new ApiFeature.NoFramework(WebViewFeature.MULTI_PROFILE, Features.MULTI_PROFILE) {
                 @Override
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/WorkLauncher.kt b/work/work-runtime/src/main/java/androidx/work/impl/WorkLauncher.kt
index f5fdeca..3dafa1c 100644
--- a/work/work-runtime/src/main/java/androidx/work/impl/WorkLauncher.kt
+++ b/work/work-runtime/src/main/java/androidx/work/impl/WorkLauncher.kt
@@ -21,7 +21,6 @@
 import androidx.work.WorkerParameters
 import androidx.work.WorkerParameters.RuntimeExtras
 import androidx.work.impl.model.WorkSpec
-import androidx.work.impl.utils.StartWorkRunnable
 import androidx.work.impl.utils.StopWorkRunnable
 import androidx.work.impl.utils.taskexecutor.TaskExecutor
 
@@ -55,8 +54,7 @@
     val workTaskExecutor: TaskExecutor,
 ) : WorkLauncher {
     override fun startWork(workSpecId: StartStopToken, runtimeExtras: RuntimeExtras?) {
-        val startWork = StartWorkRunnable(processor, workSpecId, runtimeExtras)
-        workTaskExecutor.executeOnTaskThread(startWork)
+        workTaskExecutor.executeOnTaskThread { processor.startWork(workSpecId, runtimeExtras) }
     }
 
     override fun stopWork(workSpecId: StartStopToken, @StopReason reason: Int) {
diff --git a/work/work-runtime/src/main/java/androidx/work/impl/utils/StartWorkRunnable.kt b/work/work-runtime/src/main/java/androidx/work/impl/utils/StartWorkRunnable.kt
deleted file mode 100644
index 58e8038..0000000
--- a/work/work-runtime/src/main/java/androidx/work/impl/utils/StartWorkRunnable.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2018 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.work.impl.utils
-
-import androidx.annotation.RestrictTo
-import androidx.work.WorkerParameters
-import androidx.work.impl.Processor
-import androidx.work.impl.StartStopToken
-
-/**
- * A [Runnable] that can start work on the
- * [androidx.work.impl.Processor].
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-class StartWorkRunnable(
-    private val processor: Processor,
-    private val startStopToken: StartStopToken,
-    private val runtimeExtras: WorkerParameters.RuntimeExtras?
-) : Runnable {
-    override fun run() {
-        processor.startWork(startStopToken, runtimeExtras)
-    }
-}